Regardez-moi en entier: tirez le meilleur parti de la vidéo en direct sur les plateformes mobiles



La façon la plus simple de lire une vidéo sur un appareil mobile est d'ouvrir le lien avec un lecteur existant sur le système, mais ce n'est pas toujours efficace.

Vous pouvez prendre ExoPlayer et l'optimiser, ou vous pouvez même écrire votre propre lecteur vidéo en utilisant uniquement des codecs et des sockets. L'article parlera du travail de streaming et de lecture vidéo, et comment réduire le délai de démarrage de la vidéo, réduire le temps de réponse entre le streamer et le spectateur, et optimiser la consommation d'énergie et la charge de fer.

Nous analyserons cela en utilisant des applications spécifiques à titre d'exemple: le client mobile Odnoklassniki (où les vidéos sont lues) et OK Live (où les émissions sont diffusées du téléphone en 1080p). Il n'y aura pas de master classes sur la façon de lire une vidéo par référence, avec des exemples de code. L'histoire se concentrera sur l'apparence de la vidéo de l'intérieur et comment, connaissant l'architecture générale des lecteurs vidéo et du streaming vidéo, vous pouvez comprendre n'importe quel système et l'améliorer.

Le matériel est basé sur la transcription du rapport d' Alexander Tobol ( @alatobol ) et Ivan Grigoriev ( @ivan_a ) de la conférence Mobius .




Entrée


Pour commencer - quelques chiffres sur la vidéo à Odnoklassniki.

Le trafic quotidien moyen de pointe en VOD (vidéo à la demande) est de plus d'un térabits et demi par seconde, et pour les diffusions en direct - de plus de 3 térabits par seconde.

Maintenant, il y a plus de 870 millions de vues vidéo par jour dans OK, dont plus de la moitié proviennent d'appareils mobiles.



Si vous regardez l'histoire du streaming, une vidéo mobile est apparue sur YouTube en 2007. Nous avons sauté dans ce train plus tard, mais en 2014-2015, nous avions déjà une lecture vidéo 4K sur des appareils mobiles, et ces dernières années, nous avons activement développé nos joueurs. À ce sujet et la conversation se poursuivra.

La deuxième tendance qui est apparue avec Periscope en 2015 était la diffusion à partir de téléphones. Nous avons lancé notre application OK Live, qui vous permet de diffuser même des vidéos Full HD sur les réseaux mobiles. Dans la seconde moitié du matériel, nous parlerons également de streaming.

Nous ne nous attarderons pas sur l'API pour travailler avec la vidéo, mais pour l'instant plonger profondément et essayer de découvrir ce qui se passe à l'intérieur.



Lorsque vous filmez une vidéo sur un appareil photo, elle parvient au codec, de là à la prise, puis au serveur (que ce soit en VOD ou en direct). Et puis le serveur dans l'ordre inverse le distribue au public.

Commençons par le lecteur KPI. Que voulons-nous de lui?

  • Première image rapide. Les utilisateurs ne veulent pas attendre le début de la lecture.
  • Manque de mise en mémoire tampon. Personne n'aime se heurter au torse.
  • De haute qualité. Lorsqu'il n'y avait presque pas encore de contenu 4K, nous avons déjà rendu la prise en charge 4K «dépassée»: si vous éteignez le lecteur pour cela et déterminez les performances, alors 1080p jouera parfaitement même sur des appareils faibles.
  • Exigences UX. Nous avons besoin que la vidéo soit lue dans la bande pendant le défilement, et pour la bande, nous devons pré-extraire la vidéo.


Il existe de nombreux problèmes de cette manière. Le flux de vidéo 4K est important et nous travaillons sur des appareils mobiles où il y a des problèmes avec le réseau, il existe diverses fonctionnalités de formats vidéo et de conteneurs sur différents appareils, et les appareils eux-mêmes peuvent également devenir un problème.

Où pensez-vous que la vidéo démarre plus rapidement, sur iOS ou Android?

En fait, toute réponse est correcte: cela dépend de quoi, où et comment jouer. Si nous prenons une région de la Russie avec un réseau moins bon, nous verrons que AVPlayer démarre à environ 800 millisecondes. Mais avec le même réseau, ExoPlayer sur Android, jouant un format différent, le lancera en 660 ms. Et si vous créez votre lecteur sur iOS, il pourra fonctionner encore plus rapidement.



Il y a une nuance dans la mesure où nous mesurons la moyenne pour les utilisateurs, et la puissance moyenne des appareils iOS est plus élevée que sur Android.

La première partie du matériel sera théorique: nous apprendrons ce qu'est la vidéo et à quoi ressemble l'architecture de n'importe quel lecteur Live. Et dans la deuxième partie, comparons les joueurs et parlons du moment d'écrire le vôtre.

Première partie


Qu'est-ce que la vidéo


Commençons par le plus basique. La vidéo est de 60 ou 24 images par seconde.

Évidemment, le stocker avec un ensemble complet d'images est assez cher. Par conséquent, ils sont stockés de cette manière: certaines trames sont appelées trames de référence (trames I), tandis que d'autres (trames B et trames P) sont appelées «diffs». En fait, vous avez un fichier jpg et un ensemble spécifique de modifications.



Il y a aussi le concept de GOP (groupe d'images) - c'est un ensemble indépendant d'images, qui commence par une image de référence et continue avec un ensemble de diffs. Il peut être joué indépendamment, déballé et ainsi de suite. Dans le même temps, si vous avez perdu un opornik dans le groupe, les images restantes ne sont plus pertinentes.

Il existe de nombreux algorithmes de codage, matrices de transformation, recherche de mouvement, etc. - c'est en cela que les codecs diffèrent.

Performances du codec





Le H.264 classique est connu depuis 2003 et s'est bien développé. Nous prendrons son efficacité comme base. Il travaille et joue partout. Il a un support matériel pour CPU / GPU (à la fois sur iOS, sur Android). Cela signifie qu'il existe soit une sorte de coprocesseur spécial qui peut le coder, soit des jeux d'instructions intégrés qui vous permettent de le faire rapidement. En moyenne, le support matériel offre des performances jusqu'à 10 fois plus rapides et économise la durée de vie de la batterie.

En 2010, VP8 de Google est apparu. En termes d'efficacité, il ne diffère pas du H.264. Eh bien, en fait, l'efficacité du codec est une chose très controversée. Dans le front, il est mesuré comme le rapport de la vidéo originale sur la vidéo compressée, mais il est clair qu'il existe différents artefacts vidéo. Par conséquent, nous fournissons un lien vers des comparaisons détaillées de codecs de l'Université d'État de Moscou. Mais ici, nous nous limitons au fait que VP8 se concentre sur une organisation logicielle, vous pouvez le faire glisser avec vous n'importe où, et il est généralement utilisé comme solution de rechange s'il n'y a pas de support H.264 natif.

En 2013, une nouvelle génération de codecs est apparue - H.265 (HEVC) et VP9. Le codec H.265 donne une augmentation de l'efficacité de 50%, mais sur la vidéo Android, ils ne peuvent pas être encodés, le décodeur est apparu uniquement avec Android 5.0+. Mais sur iOS, il existe un support.

Il existe une alternative à H.265 - VP9. Tout de même, mais pris en charge par Google. Eh bien, V9 est YouTube et H.265 est Netflix. Ainsi, chacun a ses propres particularités: l'un ne fonctionnera pas sur iOS, l'autre aura des problèmes sur Android. Au final, beaucoup restent sur H.264.

À l'avenir, on nous promet le codec AV1, il a déjà une implémentation logicielle, et son efficacité est 35% supérieure à celle des codecs 2013. Désormais disponible dans Chrome et Firefox, et en 2020, Google promet une prise en charge matérielle - je pense que, très probablement, nous y passerons tous.

Enfin, ils ont récemment annoncé le codec H.266 / JVEC, affirmant que tout sera meilleur et plus rapide.

Le schéma principal: plus l'efficacité du codec est élevée, plus il nécessite de ressources informatiques des appareils.

En général, par défaut, tout le monde prend H.264, puis pour des appareils spécifiques, cela peut être compliqué.

Qualité, résolution et bitrate


En 2019, vous ne surprendrez personne avec une qualité adaptative: les utilisateurs téléchargent ou diffusent des vidéos en une seule qualité, et nous coupons une ligne de différentes qualités et envoyons le plus adapté aux appareils.

Dans ce cas, il est nécessaire que la résolution vidéo soit en corrélation avec le débit binaire. Si la résolution est doublée, le débit binaire doit également doubler:



Évidemment, si vous compressez une grande résolution avec un faible débit binaire ou vice versa, il y aura soit des artefacts, soit une gravure inutile du débit binaire.

Comment le débit binaire de la vidéo encodée se compare-t-il à la quantité d'informations d'origine? Sur un écran 4K, nous pouvons lire près de 6 Gb / s d'informations (si vous comptez tous les pixels et leur fréquence à 60 images par seconde), tandis que le débit binaire du codec peut être de 50 Mb / s. Autrement dit, le codec comprime la vidéo jusqu'à 100 fois.

Technologie de livraison


Vous avez de l'audio et de la vidéo emballés avec certains codecs. Si vous le gardez à la maison, vous pouvez ajouter tout l'audio et la vidéo en ajoutant un petit index qui vous indique à quelle seconde commence l'audio et la vidéo. Mais la vidéo ne peut pas être livrée au téléphone, et pour le streaming vers le spectateur en ligne, il existe deux classes principales de protocoles: le streaming et le segment.



Le protocole de streaming implique que vous avez une sorte d'état sur le serveur, le client aussi, et qu'il envoie des données. Le serveur peut ajuster, par exemple, la qualité. Il s'agit très souvent d'une connexion UDP.

De tels protocoles sont très complexes pour le serveur et difficiles à fournir. Pour les traductions lourdement chargées, nous utilisons des protocoles segmentés qui fonctionnent au-dessus de HTTP, peuvent être mis en cache par nginx et CDN, et ils sont beaucoup plus faciles à distribuer. Et le serveur n'est responsable de rien et, dans ce cas, apatride.

À quoi ressemble la livraison des segments: nous découpons la vidéo existante en segments, les accompagnons d'un en-tête pour l'audio et la vidéo, MPEG-TS et MP4 comme exemple de transport. Au téléphone, nous donnons un manifeste avec des informations sur où et pour quelle qualité se trouve le segment, et ce manifeste peut être mis à jour périodiquement.

Historiquement, Apple fournit via HLS et Android via DASH. Voyons comment ils diffèrent.

Commençons par l'ancien HLS, il a un manifeste qui décrit toutes les qualités disponibles - faible, moyen, élevé, etc. Il existe des débits binaires de ces qualités afin que le joueur puisse immédiatement choisir la bonne. Il choisit la qualité et obtient un manifeste imbriqué avec une liste de liens vers des segments. La durée de ces segments est également indiquée.



Il y a une fonctionnalité intéressante ici: pour commencer à jouer la première image, vous devrez faire deux allers-retours supplémentaires. La première demande, vous obtenez le manifeste principal, les manifestes second imbriqués, et ensuite seulement accéder aux données elles-mêmes, ce qui n'est pas très bon.



Deuxième difficulté: HLS a été conçu pour fonctionner sur Internet via HTTP, mais le flux de transport MPEG-2 hérité a été choisi comme conteneur pour les données vidéo, qui a été développé à des fins complètement différentes: transmettre un signal d'un satellite dans des canaux bruyants. En conséquence, nous obtenons des en-têtes supplémentaires, qui dans le cas de HLS sont complètement inutiles et ne font qu'ajouter des frais généraux.



Ajoutez une surcharge réseau et une complexité d'analyse: si vous essayez de lire 4K en DASH et HLS en Chrome, vous sentirez la différence lorsque votre ordinateur "décollera" avec des paquets HLS.

Apple essaie de résoudre ce problème. En 2016, ils ont annoncé la possibilité d'utiliser le MPEG-4 fragmenté, il y avait un certain support pour DASH dans HLS, mais le RTT supplémentaire et ses fonctionnalités n'ont pas disparu.



DASH semble un peu plus simple: vous avez un manifeste avec toutes les qualités à l'intérieur, et chaque qualité est un ensemble de segments. Vous pouvez jouer un segment pour jouer dans une qualité, puis comprendre que la vitesse a augmenté, du segment suivant pour passer à un autre. Tous les segments commencent toujours par des cadres de référence, ce qui permet de basculer.

Voici une petite assiette sur laquelle choisir:



En HLS, les codecs vidéo historiquement pris en charge ne sont que H.264, en MPEG-DASH, vous pouvez pousser n'importe qui. Le principal problème de HLS est un aller-retour supplémentaire au début, il fonctionne bien sur iOS et Android avec 4.0. Et DASH est principalement pris en charge par Google (Chrome et Android) et ne peut pas être lu sur iOS.

Architecture du joueur


Nous avons trié la vidéo plus ou moins, voyons maintenant à quoi ressemble un joueur.



Commençons par la partie réseau: lors du démarrage d'une vidéo, le lecteur suit le manifeste, sélectionne en quelque sorte la qualité, puis suit le segment, le télécharge, puis il doit décoder les images, comprendre qu'il y a suffisamment d'images dans le tampon pour la lecture, puis démarrer la lecture.

L'architecture générale du joueur:



Il y a une partie réseau, une socket, d'où proviennent les données.

Après cela - un démultiplexeur ou une sorte de chose qui obtient les flux audio et vidéo d'un transport (HLS / DASH). Elle les envoie aux codecs appropriés.

Les codecs décodent la vidéo et l'audio, puis la chose la plus intéressante se produit: ils doivent être synchronisés pour que votre vidéo et votre audio soient lus simultanément. Il existe différents mécanismes basés sur des horodatages pour cela.

Ensuite, vous devez le rendre quelque part - dans Texture, Surface, GL ou Metal, n'importe où.

Et à l'entrée, il y a un contrôle de charge, qui charge les données et contrôle le tampon.

À quoi ressemble le contrôle de charge sur tous les joueurs? Il y a une certaine quantité de données à télécharger. Le joueur attend qu'ils soient téléchargés, puis commence à jouer, et nous téléchargeons plus loin. Nous avons la limite maximale de mémoire tampon, lorsque le téléchargement s'arrête. Après cela, pendant la lecture, la quantité de données dans le tampon diminue - et il y a une bordure minimale à laquelle il commence à se charger. Donc tout cela vit aussi:



À quoi ressemble le fil de boucle principal? Les joueurs sont familiers avec le concept de «tick tick», il semble être là. Il y a une partie responsable du réseau qui empile tout dans un seul tampon. Il y a un extracteur qui décompresse et l'envoie aux codecs, où son tampon intermédiaire, puis il ira pour le rendu. Et vous avez une coche qui les décale et les contrôle, traite de la synchronisation.



À l'extérieur, vous disposez d'une application qui envoie certaines commandes via une file d'attente de messages et reçoit des informations via des écouteurs. Et parfois, une contre-pression peut apparaître, ce qui réduit la qualité - par exemple, dans une situation où votre tampon est épuisé ou le rendu est incapable de faire face (par exemple, des images perdues apparaissent).

Estimateur


Lors de l'adaptation, le lecteur s'appuie sur 2 paramètres principaux: la vitesse du réseau et le tampon de données.

À quoi cela ressemble: tout d'abord, une certaine qualité est reproduite, par exemple, 720p. Vous avez un tampon croissant, de plus en plus en cache. Ensuite, la vitesse augmente, vous comprenez que vous pouvez télécharger encore plus, le tampon augmente. Et à ce moment, vous comprenez que vous franchissez certaines limites du tampon minimum lorsque vous pouvez essayer la qualité suivante.



Il est clair que vous devez l'essayer avec soin: il existe également un estimateur qui indique si vous pouvez atteindre cette qualité en termes de vitesse du réseau. Si vous vous situez dans cette évaluation et que le stock tampon le permet, vous passez, par exemple, en 1080p et continuez à jouer.

Protection contre la surpression


Avec nous, elle est apparue au fil du temps par essais et erreurs. Le besoin s'en fait sentir lorsque vous surchargez légèrement votre équipement.

Il y a une situation où le réseau s'émousse pendant la lecture ou les ressources s'épuisent sur le backend. Lorsque le lecteur reprend la lecture, il commence à rattraper son retard.

Un énorme ensemble de segments s'est accumulé dans le manifeste du joueur à ce moment, il les télécharge rapidement tous en même temps, et nous obtenons un "coup de trafic". La situation peut être aggravée si un délai d'attente se produit sur les clients et que le joueur commence à interroger à nouveau les données. Par conséquent, il est nécessaire de prévoir une contre-pression dans le système.

Le premier moyen simple que nous utilisons, bien sûr, est l'accélérateur sur le serveur. Il comprend que le trafic se termine, réduit la qualité et ralentit délibérément les clients afin de ne pas recevoir ce coup même.



Mais cela n'affecte pas très bien les estimateurs. Ils peuvent générer les mêmes «rebondissements». Par conséquent, si possible, soutenez la suppression de la qualité du manifeste. Pour ce faire, vous devez soit mettre à jour périodiquement le manifeste, ou s'il y a un canal de rétroaction, donner la commande pour supprimer la qualité, et le joueur passera automatiquement à un autre, plus bas.

Joueurs


Dans iOS, il n'y a que AVPlayer natif, mais sur Android, il y a un choix. Il existe un MediaPlayer natif, mais il existe un ExoPlayer basé sur Java open source que les applications «apportent avec eux». Quels sont leurs avantages et leurs inconvénients?

Comparez les trois:



Dans le cas du streaming adaptatif, ExoPlayer joue DASH / HLS et dispose de nombreux modules extensibles pour d'autres protocoles, tandis que AVPlayer s'aggrave.

La prise en charge des versions de système d'exploitation convient en principe à tout le monde partout.

La prérécupération, c'est quand vous savez qu'après la fin d'une vidéo, vous voulez lire ce qui suit dans la bande et la précharger.

Il y a un problème avec les corrections de bugs des joueurs natifs. Dans le cas d'ExoPlayer, vous le faites simplement rouler dans une nouvelle version de votre application, mais dans AVPlayer et MediaPlayer natif, le bogue ne sera corrigé que dans la prochaine version du système d'exploitation. Nous sommes tombés sur cela douloureusement: dans iOS 8.01, notre vidéo commençait à mal jouer, dans iOS 8.02 le portail entier cessait de fonctionner, dans 8.03 tout fonctionnait à nouveau. Et rien ne dépendait de nous dans ce cas, nous nous sommes juste assis et avons attendu qu'Apple lance la prochaine version.

L'équipe ExoPlayer parle de l'inefficacité de la consommation d'énergie dans le cas de l'audio. Il existe des recommandations générales de Google: pour lire de l'audio, utilisez MediaPlayer, pour tout le reste Exo.

Compris, nous utiliserons ExoPLayer avec DASH pour la vidéo sur Android et AVPlayer avec HLS sur iOS.

Première image rapide


Encore une fois, rappelez-vous le temps jusqu'à la première image. À quoi cela ressemble-t-il sur iOS HLS: d'abord RTT derrière le manifeste, puis un autre RTT derrière le manifeste imbriqué, alors seulement - obtenir le segment et jouer. Sous Android, un RTT c'est moins, ça démarre un peu mieux.



Taille du tampon


Voyons maintenant les tampons. Nous avons un minimum de données à télécharger avant de commencer à jouer. Dans AVPlayer, cette valeur est configurée à l'aide d'AVPlayerItem PreferredForwardBufferDuration.



Sur Android, ExoPlayer a beaucoup plus de mécanismes de configuration. Il y a le même tampon minimum qui est nécessaire pour démarrer. Mais il existe également un paramètre distinct pour le réamorçage (si votre réseau est tombé en panne, les données du tampon se sont épuisées, puis elles sont revenues):



Quel est le profit? Si vous avez un bon réseau, vous commencez rapidement et vous battez pour une première image rapide, pour la première fois vous pouvez essayer de tenter votre chance. Mais si le réseau tombe en panne pendant la lecture, il est évident que vous devez demander plus de mise en mémoire tampon pour jouer pendant le rebuffing afin qu'il n'y ait pas de problème répété.

Qualité d'origine





HLS sur iOS a un problème sympa: il commence toujours à jouer à partir de la première qualité dans le manifeste m3u8. Ce que vous lui rendrez commencera. Et seulement alors, il mesurera la vitesse de téléchargement et commencera à jouer en qualité normale. Il est clair que cela ne devrait pas être autorisé.

Optimisation logique - qualité de tri. Soit sur le serveur (en ajoutant un paramètre supplémentaire à la qualité préférée, il trie à nouveau le manifeste), soit sur le client (créez un proxy qui le fera pour vous).

Et sur Android, il existe un paramètre DefaultBandwidthMeter pour cela. Il donne une valeur qu'il considère comme la bande passante par défaut de votre bande.



Comment ça marche: il y a une énorme table de constantes dans le code, et les paramètres sont simples - le pays (région) et le type de connexion (wi-fi, 2G, 3G, 4G). Quelles sont les significations? Par exemple, si vous disposez du Wi-Fi et que vous vous trouvez aux États-Unis, votre bande passante initiale est de 5,6 Mbps. Et si la 3G est à 700 kbps.

On peut voir que, selon les estimations de Google, la 4G en Russie est 2 à 3 fois plus rapide qu'en Amérique.

Il est clair que la Russie est un grand pays, et une telle configuration ne nous convenait pas du tout. Par conséquent, si vous voulez le faire simplement, souvenez-vous de la valeur précédente pour le réseau actuel, soustrayez une unité au cas où, et démarrez-la.

Et si vous avez une grande application qui lit des vidéos dans le monde entier, collectez des statistiques sur les sous-réseaux et recommandez au serveur la qualité à partir de laquelle commencer. Gardez à l'esprit qu'après la mise en mémoire tampon, il est conseillé d'augmenter la valeur de la mémoire tampon (sur Android, cela est facilement autorisé).

Comment accélérer le rembobinage


(seek), , . , , , .



, , - . iOS, , , , ( , , ).

ExoPlayer 2.7.0 , , « ». . , .



( , ), - , Android prepare(mediaSource), seekTo(). , , , . — :



, ( , ), . ( 100 ), , .




iOS , Android legacy-.
TextureView. , , , , UI. — .

SurfaceView. , . Android- . YouTube , .

GLSurfaceView — . , .



: , ExoPlayer, 23%. «» 10%. 4% . 4% — , .

: Android


  • MediaPlayer , ExoPlayer
  • start, seek, swap
  • ,
  • view

: iOS


iOS :

  • RTT HLS AVPlayer
  • AVPlayer#pause
  • — , iOS


DASH-, « live-». :

  • cURL GCDAsyncSocket
  • AVAssetReader,
  • CADisplayLink
  • AVSampleBufferDisplayLayer


, . 28%, «» 6%. , HLS DASH 100 /, 6%.

iOS :

  • start seek
  • HLS over Fragmented mp4
  • DASH-


, .

:


, , .

  • ( mp4)
  • (ExoPlayer, AVPlayer)
  • firstFrame, seek, emptyBuffer
  • ( )
  • - , . 4, : performance, , .


— .

:


, ?



API . API iOS Android, — , .

: - wrapper , POSIX-, , .

?

  • Démarrage rapide


?

  • bandwidth
  • (N x RTT, RTT)






— . , , .

: , , . — low latency.

, — . .

— 4K. , , . , 30 , . , .


, , , . ( 100 ).

- , , .

. 100 , . , 300 kbps FullHD- 480p, FullHD . , : , , overhead-. .

:



, , . , - , , .

MediaCodec VideoToolbox ( ). Server Transcoder.

— , .


Lorsque nous commençons à nous plonger dans le streaming, nous rencontrons un certain nombre de compromis. En particulier, il y a un triangle dans les coins dont la fiabilité est la fiabilité (pas de gouttes), le débit est la bande passante (combien nous utilisons le réseau) et une faible latence est une faible latence (obtenons-nous une faible latence).



Si nous commençons à optimiser l'un de ces paramètres, les autres échoueront inévitablement. Nous ne pouvons pas tout obtenir en même temps, nous devons sacrifier quelque chose.

Protocoles


Les protocoles que nous verrons aujourd'hui: RTMP et WebRTC sont des protocoles standard, OKMP est notre protocole personnalisé.

Il convient de mentionner que RTMP fonctionne sur TCP et les deux autres sur UDP.

RTMP


Que donne-t-il? D'une certaine manière, il s'agit d'une norme prise en charge par tous les services - YouTube, Twitch, Flash, OK. Ils l'utilisent pour que les utilisateurs puissent télécharger des flux en direct. Si vous souhaitez diffuser un flux en direct vers un service tiers, vous devrez probablement travailler avec RTMP.

Le délai minimum que nous avons réussi à atteindre d'un lecteur de bande à un lecteur est de 300 ms, mais c'est dans un réseau idéal par beau temps. Lorsque nous avons un vrai réseau, le délai passe généralement à 2-3 secondes, et si tout va mal avec le réseau, il peut atteindre des dizaines de secondes.

RTMP prend en charge la modification de la résolution et du débit binaire à la volée (les autres protocoles mentionnés sont les mêmes, mais il y a des informations erronées sur RTMP qu'il n'y a pas de changement à la volée).

Parmi les inconvénients: construit sur TCP (nous expliquerons plus tard pourquoi c'est mauvais), le retard n'est pas contrôlé.

Si vous regardez le triangle, RTMP ne pourra pas donner une faible latence. Il peut être obtenu, mais pas du tout garanti.

De plus, RTMP est un peu merdique: il ne prend pas en charge les nouveaux codecs, car Adobe ne le fait pas, et la documentation est assez ancienne et tordue.



Pourquoi TCP ne convient-il pas aux diffusions en direct? TCP donne une garantie de livraison: les données que vous mettez sur le socket seront livrées exactement dans l'ordre et sous la forme dans laquelle vous les avez placées. Rien ne sera supprimé ou réorganisé. TCP le fera ou mourra. Mais cela signifie qu'une garantie de retard est exclue - il ne pourra pas supprimer les anciennes données, qui n'ont peut-être déjà pas besoin d'être envoyées. Le tampon, les arriérés et ainsi de suite commencent à augmenter.



A titre d'illustration, le problème de blocage de Head of Line. On le trouve non seulement dans le streaming, mais aussi dans de nombreux autres cas.

Qu'est ce que c'est Nous avons un tampon récepteur initialement vide. Nous recevons des données de quelque part: beaucoup de données et beaucoup de paquets IP. Nous avons reçu le premier paquet IP, et sur le récepteur en utilisant la méthode recv (), nous pouvons soustraire ce paquet, obtenir des données, perdre, rendre. Mais soudain, le deuxième paquet a été perdu. Que se passe-t-il ensuite?

Pour récupérer un paquet IP perdu, TCP doit retransmettre. Pour que cela se produise, vous devez dépenser RTT, tandis que la retransmission peut également être perdue, et nous allons procéder par cycles. S'il existe de nombreux packages, cela se produira certainement.

Après cela, beaucoup de données que nous ne pouvons pas lire, car nous attendons le deuxième paquet. Bien qu'il ait montré une trame de diffusion qui s'est produite il y a cinq minutes et n'est plus nécessaire.

Pour comprendre un autre problème, regardons l'adaptation RTMP. Nous faisons l'adaptation côté expéditeur. Si le réseau ne peut pas cramper les données à la vitesse à laquelle elles sont placées dans le socket, le tampon est rempli et le socket dit EWOULDBLOCK ou est bloqué si le blocage est utilisé à ce moment.



Ce n'est qu'à ce moment que nous comprenons que nous avons des problèmes et que nous devons réduire la qualité.

Disons que nous avons un réseau avec une vitesse spécifique de 4 Mbps. Nous avons choisi une taille de socket de 250 Ko (correspondant à 0,5 seconde à notre vitesse). Soudain, le réseau a échoué 10 fois - c'est une situation normale. Nous avons 400 kbps. Le tampon s'est rapidement rempli en une demi-seconde et ce n'est qu'à ce moment-là que nous comprenons que nous devons arrêter.



Mais maintenant, le problème est que nous avons un tampon de 250 Ko qui sera transmis pendant 5 secondes. Nous sommes déjà complètement à la traîne: nous devons d'abord pousser les anciennes données, et ce n'est qu'alors que les nouvelles et les adaptées iront rattraper le temps réel.

Que faire Ici, notre «triangle de compromis» est juste pertinent.



  • Nous pouvons réduire le tampon de l'expéditeur, mis au lieu de 0,5 sec - 0,1 sec. Mais nous perdons de la bande passante, car nous allons souvent «paniquer» et basculer vers le bas. De plus, TCP fonctionne de telle manière que si vous mettez un tampon émetteur plus petit que RTT, vous ne pouvez pas utiliser toute la bande passante du canal, il diminuera de plusieurs fois.
  • Nous pouvons augmenter la mémoire tampon du récepteur. Avec un grand tampon, les données arrivent, nous pouvons aplanir certaines irrégularités au sein du tampon. Mais, bien sûr, nous perdons une faible latence, car nous avons immédiatement mis en place un tampon de 5 secondes.
  • Nous pouvons supprimer de manière agressive les anciennes données. Dans TCP, la seule option pour cela est de rompre la connexion et de la recréer. Nous perdons en fiabilité, car pour le moment le joueur n'a rien à montrer.


WebRTC


Il s'agit d'une bibliothèque C ++ qui prend déjà en compte l'expérience et s'exécute sur UDP. Builds sous iOS, Android, est intégré dans les navigateurs, prend en charge HTML5. Puisqu'il est emprisonné pour les appels P2P, le délai est de 0,1 à 1 seconde.



Parmi les inconvénients: il s'agit d'une bibliothèque monolithique avec une abondance d'héritage qui ne peut pas être supprimée. De plus, en raison de sa concentration sur les appels P2P, il priorise une faible latence. Il semblerait que nous voulions cela, mais pour cela, elle sacrifie d'autres paramètres. Et il n'y a pas de paramètres pour changer les priorités.

Il convient également de garder à l'esprit que la bibliothèque est orientée client pour une conversation entre deux clients sans serveur. Le serveur doit être recherché par un tiers ou écrire le vôtre.

Que choisir - RTMP ou WebRTC? Nous avons implémenté les deux protocoles et les avons testés dans différents scénarios. Sur le graphique, WebRTC a un faible retard, mais un faible débit, tandis que RTMP a le contraire. Et entre eux, il y a un trou.

Et nous voulions faire un protocole qui couvre complètement ce trou et peut fonctionner à la fois en WebRTC et en mode RTMP. Ils l'ont fait et l'ont nommé OKMP.


Okmp


Il s'agit d'un protocole flexible pour UDP.

Prend en charge le multiplexage. Qu'est-ce que cela signifie: il y a plusieurs canaux à l'intérieur de la session (dans le cas de OK Live - le gestionnaire, audio et vidéo). Au sein de chaque canal, les données sont garanties d'être livrées dans un certain ordre (mais elles ne sont pas elles-mêmes garanties d'être livrées), et l'ordre entre les canaux n'est pas garanti, car ce n'est pas important.

Qu'est-ce que ça donne? Tout d'abord, cela nous a permis de prioriser les chaînes. Nous pouvons dire que le canal de contrôle a une priorité élevée, le son est moyen et la vidéo est faible. La gigue vidéo et la diffusion vidéo inégale sont plus faciles à masquer, et l'utilisateur a moins de problèmes de problèmes vidéo que de bégaiement désagréable de l'audio.



De plus, notre protocole dispose d'une garantie de livraison optionnelle. Nous pouvons dire que sur un certain canal, nous travaillons en mode TCP, avec une livraison garantie, et sur le reste, nous autorisons quelques baisses.

Grâce à cela, une garantie de retard peut être faite: il n'y a aucune garantie de retard sur le canal TCP, mais sur les autres où les suppressions sont autorisées, un seuil est fixé, après quoi les données commencent à chuter et nous arrêtons de livrer les anciennes données.

Par exemple, pour l'audio, cela représente 1 seconde et pour la vidéo, 0,5 seconde. Pourquoi le seuil est-il différent? Il s'agit d'un autre mécanisme de priorisation. Puisqu'il est plus important pour nous que l'audio soit fluide, nous commençons par supprimer la vidéo.

Notre protocole est configuré de manière flexible: il n'y a pas de mode de fonctionnement unique, nous modifions les paramètres à la volée pour passer au mode souhaité sans effets visibles pour l'utilisateur. Pourquoi? Par exemple, pour les mêmes appels vidéo: si un appel vidéo démarre dans un flux, nous le transférons tranquillement en mode faible latence. Et puis revenez en mode débit pour une qualité maximale.
Difficultés de mise en œuvre



Bien sûr, si vous décidez d'écrire votre protocole en UDP, vous rencontrerez des problèmes. En utilisant TCP, nous obtenons des mécanismes que nous devrons écrire nous-mêmes sur UDP:

  • Mise en paquets / dépacketisation. Vous devez découper les données en paquets d'une taille d'environ 1,5 Ko afin qu'ils s'intègrent dans le réseau MTU.
  • Réorganisation. Vous envoyez des paquets dans un ordre, et ils sont réorganisés en cours de route et arrivent dans un autre. Pour surmonter cela, vous devez définir la séquence avec le numéro de package et les réorganiser sur le récepteur.
  • Pertes. Bien sûr, il y a des pertes. Lorsqu'une perte se produit, le récepteur doit dire séparément à l'expéditeur que "J'ai reçu ces paquets, mais je ne les ai pas reçus", et l'expéditeur doit retransmettre les paquets manquants. Ou laissez-les tomber.
  • Contrôle de flux Si le récepteur ne reçoit pas de données, ne suit pas la vitesse à laquelle nous le poussons, les données peuvent commencer à se perdre, nous devons traiter cette situation. Dans le cas de TCP, le socket d'envoi sera bloqué et dans le cas d'UDP, il ne sera pas bloqué, vous devez vous comprendre que le récepteur ne reçoit pas de données et réduire la quantité de données envoyées.
  • Contrôle de la congestion. Une chose similaire, seulement dans ce cas, le réseau est mort. Si nous envoyons des paquets au réseau décédé, nous détruirons non seulement notre connexion, mais aussi les voisins.
  • Cryptage Besoin de prendre soin du cryptage
  • ... et bien plus


OKMP vs RTMP


Qu'avons-nous obtenu lorsque nous avons commencé à utiliser OKMP au lieu de RTMP?

  • L'augmentation moyenne du débit binaire OKLive est de 30%.
  • Gigue (mesure de l'arrivée inégale de paquets) - 0% (en moyenne la même).
  • Audio Jitter - -25%
  • Vidéo de gigue - 40%


Changements audio et vidéo - démonstration des priorités dans notre protocole. L'audio nous donne une priorité plus élevée, et il a commencé à venir plus facilement grâce à la vidéo.

Comment choisir un protocole pour le streaming





Si vous avez besoin d'une faible latence - WebRTC.

Si vous souhaitez travailler avec des services externes, publier des vidéos sur des services tiers, vous devrez utiliser RTMP.

Si vous voulez un protocole adapté à vos scripts, implémentez le vôtre.

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


All Articles