Temps de lecture estimé : 3 minutes
Dans le billet Qu’est-ce-que c’est le streaming à débit adaptatif ? nous avons vu en quoi l’assouplissement des contraintes de qualité était primordial pour l’universalité du streaming.
Rentrons maintenant dans la technique. Dans le streaming simple, le fichier est découpé en segments (ou chunks) de telle sorte que le fichier global n’a pas besoin d’être téléchargé entièrement pour commencer la lecture, uniquement le segment. Ce sont ces éléments qui sont placés dans le buffer.
Disons-le tout net, le streaming adaptatif (ou ABR : Adaptative BitRate streaming) fonctionne exactement de la même manière.
Évidemment, cette adaptation ne se fait pas magiquement. On trouve deux protocoles majoritaires permettant l’ABR : le HLS et le DASH. Tous deux forgent des fichiers d’index contenant le fichier multimédia dans différentes qualités, permettant ainsi au client de basculer de l’un à l’autre à la volée. Ces différents fichiers sont eux-mêmes découpés en segments, comme tout fichier « streamable ».
NB: Voir comment ces fichiers sont techniquement produits n’est pas l’objectif de ce billet, nous aurons peut-être l’occasion de le voir dans un autre.
Le format index de HLS est le .m3u8
et se compose comme suit :
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=150000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/low/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=240000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/lo_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=440000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/hi_mid/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=640000,RESOLUTION=640x360,CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/high/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=64000,CODECS="mp4a.40.5"
http://example.com/audio/index.m3u8
DASH quant à lui forge un .mpd
et se présente sous la forme d’un XML :
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" minBufferTime="PT1.500000S" type="static" mediaPresentationDuration="PT0H9M56.46S" profiles="urn:mpeg:dash:profile:isoff-live:2011">
<ProgramInformation moreInformationURL="http://gpac.sourceforge.net">
<Title>dashed/BigBuckBunny_2s_simple_2014_05_09.mpd generated by GPAC</Title>
</ProgramInformation>
<Period duration="PT0H9M56.46S">
<AdaptationSet segmentAlignment="true" group="1" maxWidth="480" maxHeight="360" maxFrameRate="24" par="4:3">
<SegmentTemplate timescale="96" media="bunny_$Bandwidth$bps/BigBuckBunny_2s$Number$.m4s" startNumber="1" duration="192" initialization="bunny_$Bandwidth$bps/BigBuckBunny_2s_init.mp4"/>
<Representation id="854x480 595.0kbps" mimeType="video/mp4" codecs="avc1.42c01e" width="854" height="480" frameRate="24" sar="1:1" startWithSAP="1" bandwidth="595491"/>
<Representation id="1280x720 1.5Mbps" mimeType="video/mp4" codecs="avc1.42c01f" width="1280" height="720" frameRate="24" sar="1:1" startWithSAP="1" bandwidth="1546902"/>
<Representation id="1920x1080 2.1Mbps" mimeType="video/mp4" codecs="avc1.42c032" width="1920" height="1080" frameRate="24" sar="1:1" startWithSAP="1" bandwidth="2133691"/>
</AdaptationSet>
</Period>
</MPD>
Bien que le serveur permette l’adaptation, le terme adaptatif est tourné vers le client car c’est lui qui connaît sa propre situation, l’intelligence doit donc se trouver de son côté. Étudions donc à titre d’exemple un client libre sur Github : hls.js.
La définition de la fonction hls.ts::nextLoadLevel()
nous mène moyennant détour à src/controller/abr-controller.ts::getNextABRAutoLevel()
. La partie intéressante est celle-ci :
// https://github.com/video-dev/hls.js/blob/85daa496ffd87dc0b27107a2b175ed950a450687/src/controller/abr-controller.ts#L339
let bestLevel = this.findBestLevel(
avgbw, // moyenne pondérée et échantillonnée de la bande passante
minAutoLevel, // rendu minimum possible
maxAutoLevel, // rendu maximum possible, potentiellement plafonné à la taille du lecteur
bufferStarvationDelay, // délai avant l'expiration du buffer
config.abrBandWidthFactor, // facteur d'ajustement bas de avgbw
config.abrBandWidthUpFactor // facteur d'ajustement haut de avgbw
);
Cette fonction trie les rendus par ordre de qualités décroissantes et retourne celui correspondant à la bande passante moyenne mais minimisant la bufferisation. Le rendu choisi est téléchargé et s’accumule au buffer, adaptant ainsi la qualité du stream aux capacités du client.
Le streaming adaptatif fonctionne de façon assez logique au final, sans être compliqué à outrance. En tant que producteur de contenus multimédias, nous avons tout à gagner à le mettre en place pour offrir davantage de possibilités à nos consommateurs.
Comme d’habitude, vous pouvez retrouver le code pour essayer par vous-même sur le dépôt d’exemple.
Sources :
Ce billet vous a plu ? Partagez-le sur les réseaux…
… Ou inscrivez-vous à la newsletter pour ne manquer aucun article (Si vous ne voyez pas le formulaire, désactivez temporairement uBlock).