Le problème du premier visualiseur ou la difficile conversion des flux vidéo WebRTC en HLS


Egor ferma le couvercle de l'ordinateur portable et se frotta les yeux rouges par manque de sommeil. "Les clients continuent de se plaindre du gel du flux, le nouveau groupe de correctifs n'a pas aidé du tout! Alors, que faire avec ce HLS (censuré)?" Il a dit dans le vide de l'étude.


Le navigateur n'est pas seulement hypertexte, mais aussi un streamer


Les navigateurs ont acquis des joueurs depuis longtemps, mais avec un encodeur vidéo et le streaming, l'histoire est différente. Désormais, dans presque tous les navigateurs de la dernière version, vous pouvez trouver des modules d'encodage, de streaming, de décodage et de lecture. Ces fonctions sont disponibles via l'API JavaScript et l'implémentation est appelée Web Real Time Communications ou WebRTC. Cette bibliothèque intégrée aux navigateurs peut faire beaucoup: capturer de la vidéo à partir d'une caméra intégrée, virtuelle ou USB, compresser avec les codecs H.264, VP8, VP9, ​​l'envoyer au réseau via le protocole SRTP, c'est-à-dire fonctionne comme un encodeur de streamer vidéo logiciel. En conséquence, nous voyons un navigateur qui a quelque chose de similaire à ffmpeg ou gstreamer sous le capot, qui comprime bien la vidéo, diffuse sur RTP et lit les flux vidéo.


WebRTC vous donne la liberté d'implémenter une variété de cas de streaming en JavaScript:


  • diffuser le flux du navigateur vers le serveur pour enregistrement et distribution ultérieure
  • poste à poste
  • lire le flux d'un autre utilisateur et envoyer le vôtre (chat vidéo)
  • convertir d'autres protocoles par le serveur, par exemple RTMP, RTSP, etc., et jouer dans le navigateur en tant que WebRTC

Les scripts de contrôle de flux raffinés peuvent ressembler à ceci:


//      session.createStream({name:”mystream”}).publish(); //   session.createStream({name:”mystream”}).play(); 

HLS fonctionne lorsque WebRTC ne fonctionne pas


WebRTC fonctionne dans les dernières versions des navigateurs, cependant, il existe deux des facteurs suivants: 1) Tous les utilisateurs ne mettent pas à jour les navigateurs en temps opportun et peuvent très bien s'asseoir sur une sorte de Chrome pendant trois ans. 2) Presque une fois par semaine, des mises à jour sont publiées et de nouveaux navigateurs, WebView, ainsi que d'autres clients et messagers instantanés qui peuvent surfer sur Internet. Inutile de dire que tous ne prennent pas en charge WebRTC, et si c'est le cas, il peut être assez tronqué. Voyez comment les choses vont maintenant:



Maux de tête séparés - les appareils Apple préférés de tous. Ils ont récemment reçu un soutien pour WebRTC et, parfois, sont surprenants dans leur comportement par rapport aux navigateurs Webkit orthodoxes. Et lorsque WebRTC ne fonctionne pas ou ne fonctionne pas très bien, HLS fonctionne très bien. À cet égard, la compatibilité est requise, et quelque chose comme un convertisseur qui convertira WebRTC en HLS et le lira sur presque tous les appareils.


Initialement, HLS n'a pas été conçu pour les flux en temps réel. En effet, quelle peut être la durée de la vidéo sur HTTP? La tâche de HLS est de couper la vidéo en morceaux et de la livrer au lecteur en douceur, sans précipitation, en la téléchargeant une par une. Le lecteur HLS attend un flux vidéo strictement formé et fluide. Et ici, un conflit survient, car WebRTC, au contraire, peut se permettre de perdre des paquets en raison d'exigences en temps réel et d'une faible latence et avoir un FPS / GOP flottant et un débit binaire variable - pour être l'exact opposé de HLS en termes de prévisibilité et de dimensionnalité du flux.


Une approche évidente - la dépackétisation WebRTC (SRTP) et la conversion ultérieure en HLS, peuvent ne pas fonctionner dans le lecteur Apple HLS natif ou fonctionner sous une forme inadaptée à la production avec des frises. Un lecteur natif signifie ici un lecteur utilisé dans Apple iOS Safari, Mac OS Safari, Apple TV.


Par conséquent, si vous remarquez la frise HLS dans le lecteur natif, c'est peut-être cela, et la source du flux est WebRTC ou un autre flux dynamique avec un balisage inégal. De plus, dans la mise en œuvre de lecteurs natifs d'Apple, il existe un comportement qui ne peut être compris que de manière empirique. Par exemple, le serveur doit commencer à envoyer des segments HLS immédiatement, immédiatement après le retour de la liste de lecture m3u8. Le retard par seconde menace de geler. Si la configuration du flux binaire a changé au cours du processus (ce qui est assez fréquent avec le streaming WebRTC), il y aura également une frise.


Lutte contre les frises chez les joueurs natifs


Ainsi, la dépackétisation et la mise en paquets WebRTC directes et honnêtes dans HLS ne fonctionnent généralement pas. Dans le serveur vidéo en streaming Web Call Server (WCS) , nous résolvons le problème de deux manières, et nous proposons la troisième alternative:


1) Transcodage.


C'est le moyen le plus fiable d'aligner le flux WebRTC sur les exigences HLS, de définir le GOP, le FPS, etc. souhaités. Cependant, dans certains cas, le transcodage n'est pas une bonne solution, par exemple, le transcodage de flux 4k de vidéo VR est une idée médiocre. Ces flux lourds sont très coûteux à transcoder en termes de temps CPU ou de ressources GPU.



2) Adaptation et alignement du flux WebRTC à la volée selon les exigences du HLS.


Ce sont des analyseurs spéciaux qui analysent le flux binaire H.264 et le corrigent pour les fonctionnalités / bogues des lecteurs Apple HLS natifs. Ici, nous devons admettre que les joueurs non natifs comme video.js et hls.js sont plus tolérants envers les flux avec un débit binaire dynamique et FPS, qui est WebRTC et ne ralentit pas là où l'implémentation de référence d'Apple HLS tombe essentiellement dans un gel perpétuel.



3) Utilisez RTMP comme source de flux au lieu de WebRTC.


Malgré le fait que le flash soit retiré, le protocole RTMP est activement utilisé pour le streaming, prenez le même OBS Studio. Et je dois admettre que les encodeurs RTMP produisent généralement des flux plus homogènes que WebRTC et ne produisent donc pratiquement pas de frises dans HLS, c'est-à-dire La conversion RTMP> HLS du point de vue des frises semble beaucoup plus appropriée, y compris dans les lecteurs HLS natifs. Par conséquent, si le streaming est effectué à partir du bureau et d'OBS, il est préférable de l'utiliser pour la conversion en HLS. Si la source est un navigateur Chrome, alors RTMP ne peut pas être utilisé sans installer de plugins, et ici uniquement WebRTC.



Les trois méthodes décrites ci-dessus sont testées et fonctionnent, il est donc possible de choisir en fonction des conditions de la tâche.


WebRTC à HLS sur CDN


Certains problèmes peuvent attendre dans un système distribué lorsque plusieurs serveurs de distribution de flux WebRTC sont situés entre la source de flux WebRTC et le lecteur HLS, à savoir CDN , dans notre cas, basé sur le serveur WCS. Cela ressemble à ceci: il y a Origin - un serveur qui reçoit un flux WebRTC, il y a des serveurs Edge - qui distribuent ce flux, y compris HLS. Il peut y avoir de nombreux serveurs, ce qui permet une mise à l'échelle horizontale du système. Par exemple, 1000 serveurs HLS peuvent être connectés à un serveur Origin, dans ce cas, la capacité du système est mise à l'échelle 1000 fois.



Le problème a déjà été identifié un peu plus haut, et ce problème se pose généralement dans les lecteurs natifs: iOS Safari, Mac OS Safari, Apple TV. Par natif, nous entendons un lecteur qui fonctionne avec une indication directe de l'URL de la liste de lecture dans la balise, par exemple, <video src="https://host/test.m3u8"/> . Dès que le joueur a demandé une liste de lecture, et que cette action est en fait la première étape de la lecture du flux HLS, le serveur doit immédiatement, sans délai, commencer à envoyer des segments vidéo HLS. Si le serveur ne commence pas à donner des segments immédiatement, le joueur décide qu'il a été trompé et arrête de jouer. Encore une fois, ce comportement est typique des lecteurs HLS natifs d'Apple, mais nous ne pouvons pas dire aux utilisateurs - "veuillez ne pas utiliser iPhone Mac et Apple TV pour lire les flux HLS", les utilisateurs ne comprendront pas.


Ainsi, lorsque vous essayez de lire le flux HLS sur le serveur Edge, le serveur doit immédiatement commencer à renvoyer des segments, mais comment le fera-t-il s'il n'a pas de flux? En effet, lors de la tentative de lecture d'un flux sur ce serveur est manquant. La logique CDN fonctionne sur le principe du chargement différé - nous ne dirigerons pas le flux vers le serveur jusqu'à ce que quelqu'un demande ce flux sur ce serveur. Il y a un problème de connexion du premier - le premier qui a demandé le flux HLS au serveur Edge et a eu l'insouciance de le faire du joueur natif d'Apple recevra une frise pour la raison qu'il faut un certain temps pour commander ce flux depuis le serveur Origin, pour l'obtenir sur Edge et procéder au découpage HLS. Même si cela prend trois secondes, le joueur ne l'enregistrera pas. Il ira dans la frise.



Là encore, deux décisions se profilent: l'une est normale, l'autre pas très. On pourrait abandonner l'approche Lazy Loading dans le CDN et envoyer du trafic à tous les nœuds, qu'il y ait ou non des téléspectateurs. Une solution, peut-être adaptée à ceux qui ne sont pas limités en termes de trafic et de ressources informatiques. Origin génèrera du trafic vers tous les serveurs Edge, par conséquent, tous les serveurs et le réseau entre eux seront constamment chargés. Ce schéma ne conviendrait peut-être qu'à certaines solutions spécifiques avec un petit nombre de flux entrants. Lors de la réplication d'un grand nombre de threads, un tel schéma sera clairement inefficace en termes de ressources. Et si vous vous souvenez que nous ne résolvons que le «problème de la première connexion à partir du navigateur natif», il est clair que cela n'en vaut pas la peine.



La deuxième option est plus élégante, mais aussi une solution de contournement. Nous donnons au premier utilisateur connecté une image vidéo, mais ce n'est toujours pas le flux qu'il souhaite voir - c'est un préchargeur. Comme nous devons donner quelque chose maintenant et le faire immédiatement, mais nous n'avons pas le flux source (il est toujours commandé et livré depuis Origin), nous décidons de demander au client d'attendre un peu et de lui montrer une vidéo du préchargeur avec une animation animée. L'utilisateur attend quelques secondes, le préchargeur tourne et lorsque le flux réel arrive, l'utilisateur commence à afficher le flux réel. En conséquence, le premier utilisateur a vu le préchargeur, et les suivants qui se sont enfin connectés ont vu le flux HLS normal provenant du CDN, travaillant sur le principe du chargement différé. Problème d'ingénierie résolu.


Mais pas jusqu'au bout


Il semblerait que tout fonctionne très bien. Le CDN fonctionne, les flux HLS sont extraits des serveurs Edge et le problème de la première connexion est résolu. Et voici un autre piège - nous donnons le préchargeur dans un rapport d'aspect fixe de 16: 9, et CDN peut inclure des flux de n'importe quel format: 16: 9, 4: 3, 2: 1 (vidéo VR). Et c'est un problème, car si vous donnez au lecteur un préchargeur au format 16: 9, et que le flux commandé sera au format 4: 3, alors le joueur natif attend à nouveau la frise.


Par conséquent, une nouvelle tâche se pose - vous devez savoir avec quel format le flux entre dans le CDN et donner au préchargeur dans le même rapport. Une caractéristique des flux WebRTC est la préservation du rapport d'aspect lors du changement de résolution et pendant le transcodage - si le navigateur décide de réduire la résolution, il l'abaisse dans le même rapport. Si le serveur décide de transcoder le flux, il conserve les proportions dans la même proportion. Par conséquent, il est logique que si nous voulons afficher le préchargeur pour HLS, nous le montrons dans le même rapport d'aspect dans lequel le flux entre.



Le CDN fonctionne comme suit: lorsque le trafic pénètre dans le serveur d'origine, il informe les autres serveurs du réseau, y compris les serveurs Edge, du nouveau flux. Le problème est qu'à ce stade, la résolution du flux source peut ne pas encore être connue. La résolution est portée par les configurations de flux binaire H.264 avec l'image clé. Par conséquent, il peut arriver que le serveur Edge reçoive des informations indiquant qu'il existe un flux, mais qu'il ne connaîtra pas sa résolution et son rapport hauteur / largeur, ce qui ne lui permettra pas de générer correctement le préchargeur. À cet égard, il est nécessaire de signaler la présence d'un flux dans le CDN uniquement s'il y a une image clé - cela est garanti pour donner au serveur Edge des informations sur la taille et permettre au préchargeur correct d'être généré pour éviter «le problème du premier visualiseur connecté».



Résumé


La conversion de WebRTC en HLS fournit généralement des frises lorsqu'il est joué dans des lecteurs Apple natifs. Le problème est résolu en analysant et en ajustant le flux binaire H.264 aux exigences HLS d'Apple, soit en transcodant, soit en utilisant la migration vers le protocole RTMP et l'encodeur comme source de flux. Dans un réseau distribué avec chargement paresseux de flux, il y a un problème du premier visualiseur connecté, qui est résolu en utilisant le préchargeur et en déterminant la résolution du côté du serveur d'origine - le point d'entrée du flux dans le CDN.


Les références


Serveur d'appel Web - Serveur WebRTC


CDN de streaming WebRTC à faible latence - CDN basé sur WCS


Lecture de flux vidéo WebRTC et RTMP sur HLS - Fonctions serveur pour convertir des flux de diverses sources en HLS

Source: https://habr.com/ru/post/fr480432/


All Articles