Fermer

mars 27, 2025

Streaming vidéo adaptatif avec dash.js dans React

Streaming vidéo adaptatif avec dash.js dans React


J’ai récemment été chargé de créer des rouleaux vidéo qui devaient être lus en douceur sous un réseau lent ou sur des appareils bas de gamme. J’ai commencé avec le HTML5 natif <video> Tag mais frappez rapidement un mur – il ne le coupe pas lorsque les connexions sont lentes ou que les appareils sont sous-alimentés.

Après quelques recherches, j’ai trouvé que Streaming de débit binaire adaptatif était la solution dont j’avais besoin. Mais voici la partie frustrante: trouver un guide complet et adapté aux débutants a été si difficile. Les ressources sur MDN et d’autres sites Web ont été utiles mais manquaient du tutoriel de bout en bout que je cherchais.

C’est pourquoi j’écris cet article: pour vous fournir le guide étape par étape que j’aurais aimé trouver. Je vais combler l’écart entre la rédaction de scripts FFMPEG, le codage des fichiers vidéo et la mise en œuvre du lecteur vidéo compatible Dash (Dash.js) Avec des exemples de code, vous pouvez suivre.

Aller au-delà du HTML5 natif <video> Étiqueter

Vous vous demandez peut-être pourquoi vous ne pouvez pas simplement compter sur le HTML <video> élément. Il y a une bonne raison à cela. Comparons la différence entre un natif <video> élément et streaming vidéo adaptatif dans les navigateurs.

Téléchargement progressif

Avec le téléchargement progressif, votre navigateur télécharge linéairement le fichier vidéo à partir du serveur via HTTP et démarre la lecture tant qu’elle a tamponné suffisamment de données. C’est le comportement par défaut du <video> élément.

<video src="https://smashingmagazine.com/2025/03/adaptive-video-streaming-dashjs-react/rabbit320.mp4" />

Lorsque vous jouez la vidéo, consultez l’onglet réseau de votre navigateur et vous verrez plusieurs demandes avec le 206 Partial Content code d’état.

Demandes de gamme HTTP 206
(Grand aperçu)

Il utilise Demandes de gamme HTTP 206 Pour récupérer le fichier vidéo en morceaux. Le serveur envoie des gammes d’octets spécifiques de la vidéo à votre navigateur. Lorsque vous cherchez, le navigateur fera plus de demandes de plage demandant de nouvelles gammes d’octets (par exemple, «donnez-moi des octets 1 000 000 à 2 000 000»).

En d’autres termes, cela ne va pas tout entier en une seule fois. Au lieu de cela, il fournit des octets partiels des gammes d’octets partiels du fichier vidéo MP4 unique à la demande. Ceci est toujours considéré comme un téléchargement progressif Parce qu’un seul fichier est récupéré sur HTTP – il n’y a pas de bande passante ni d’adaptation de qualité.

Si le serveur ou le navigateur ne prend pas en charge les demandes de plage, le fichier vidéo entier sera téléchargé en une seule demande, renvoyant un 200 OK code d’état. Dans ce cas, la vidéo ne peut commencer à lire qu’une fois le fichier entier terminé le téléchargement.

Les problèmes? Si vous êtes sur une connexion lente en essayant de regarder une vidéo haute résolution, vous attendez longtemps avant le début de la lecture.

Streaming de débit binaire adaptatif

Au lieu de servir un seul fichier vidéo, Streaming de débit binaire adaptatif (ABR) divise la vidéo en plusieurs segments à différents débits et résolutions. Pendant la lecture, l’algorithme ABR sélectionnera automatiquement le segment de la plus haute qualité qui peut être téléchargé à temps pour la lecture en douceur en fonction de votre connectivité réseau, de votre bande passante et d’autres capacités d’appareil. Il continue de s’adapter partout pour s’adapter aux conditions changeantes.

Cette magie se produit à travers deux technologies de navigateur clés:

  • Extension de source de média (MSE)
    Il permet de passer un MediaSource s’opposer au src attribuer <video>permettant d’envoyer plusieurs SourceBuffer objets qui représentent des segments vidéo.
<video src="blob:https://example.com/6e31fe2a-a0a8-43f9-b415-73dc02985892" />
  • API Media Capacities
    Il fournit des informations sur les capacités de décodage vidéo et d’encodage de votre appareil, permettant à ABR de prendre des décisions éclairées sur la résolution à fournir.

Ensemble, ils permettent la fonctionnalité de base de l’ABR, desservant des morceaux vidéo optimisés pour vos limitations de périphériques spécifiques en temps réel.

Protocoles de streaming: MPEG-Dash Vs. HLS

Comme mentionné ci-dessus, pour diffuser les médias de manière adaptative, une vidéo est divisée en morceaux à différents niveaux de qualité à différents moments. Nous devons faciliter le processus de commutation entre ces segments de manière adaptative en temps réel. Pour y parvenir, le streaming ABR repose sur des protocoles spécifiques. Les deux protocoles ABR les plus courants sont:

  • Mpeg-dash,
  • HTTP Streaming en direct (HLS).

Ces deux protocoles utilisent HTTP pour envoyer des fichiers vidéo. Par conséquent, ils sont compatibles avec les serveurs Web HTTP.

Cet article se concentre sur MPEG-Dash. Cependant, il convient de noter que Dash n’est pas pris en charge par les appareils ou les navigateurs Apple, comme mentionné dans Article de Mux.

Mpeg-dash

MPEG-Dash permet le streaming adaptatif:

  • Un fichier de description de présentation des médias (MPD)
    Ce fichier manifeste XML contient des informations sur la façon de sélectionner et de gérer des flux en fonction des règles adaptatives.
  • Fichiers multimédias segmentés
    Les fichiers vidéo et audio sont divisés en segments à différentes résolutions et durées à l’aide de codecs et formats conformes à la dash MPEG.

Du côté client, un lecteur vidéo conforme à Dash lit le fichier MPD et surveille en continu la bande passante du réseau. Sur la base de la bande passante disponible, le lecteur sélectionne le débit binaire approprié et demande le morceau vidéo correspondant. Ce processus se répète tout au long de la lecture, garantissant une qualité fluide et optimale.

Maintenant que vous comprenez les fondamentaux, construisons notre lecteur vidéo adaptatif!

Étapes pour construire un lecteur vidéo en streaming de débit adaptatif

Voici le plan:

  1. Transcode la vidéo MP4 en interprétations audio et vidéo à différentes résolutions et débats binaires avec FFMPEG.
  2. Générez un fichier MPD avec FFMPEG.
  3. Servir les fichiers de sortie du serveur.
  4. Construisez le lecteur vidéo compatible Dash pour lire la vidéo.

Installer ffmpeg

Pour les utilisateurs de macOS, installez FFMPEG à l’aide de Brew en exécutant la commande suivante dans votre terminal:

brew install ffmpeg

Pour d’autres systèmes d’exploitation, veuillez Reportez-vous à la documentation de FFMPEG.

Générer un rendu audio

Ensuite, exécutez le script suivant pour extraire la piste audio et encodez au format WebM pour la compatibilité Dash:

ffmpeg -i "input_video.mp4" -vn -acodec libvorbis -ab 128k "audio.webm"
  • -i "input_video.mp4": Spécifie le fichier vidéo d’entrée.
  • -vn: Désactive le flux vidéo (sortie audio uniquement).
  • -acodec libvorbis: Utilise le libvorbis codec pour coder l’audio.
  • -ab 128k: Définit le débit audio pour 128 kbps.
  • "audio.webm": Spécifie le fichier audio de sortie au format Webm.

Générer des interprétations vidéo

Exécutez ce script pour créer trois interprétations vidéo avec des résolutions et des débits variables. La plus grande résolution doit correspondre à la taille du fichier d’entrée. Par exemple, si la vidéo d’entrée est 576 × 1024 À 30 images par seconde (FPS), le script génère des rendus optimisés pour la lecture vidéo verticale.

ffmpeg -i "input_video.mp4" -c:v libvpx-vp9 -keyint_min 150 -g 150 \
-tile-columns 4 -frame-parallel 1 -f webm \
-an -vf scale=576:1024 -b:v 1500k "input_video_576x1024_1500k.webm" \
-an -vf scale=480:854 -b:v 1000k "input_video_480x854_1000k.webm" \
-an -vf scale=360:640 -b:v 750k "input_video_360x640_750k.webm"
  • -c:v libvpx-vp9: Utilise le libwx-vp9 comme l’encodeur vidéo VP9 pour WebM.
  • -keyint_min 150 et -g 150: Définir un Intervalle de l’ordre clé de 150 images (environ toutes les 5 secondes à 30 ips). Cela permet une commutation de débit binaire toutes les 5 secondes.
  • -tile-columns 4 et -frame-parallel 1: Optimiser les performances de codage grâce à un traitement parallèle.
  • -f webm: Spécifie le format de sortie comme WebM.

Dans chaque interprétation:

  • -an: Exclut l’audio (sortie vidéo uniquement).
  • -vf scale=576:1024: Évolue la vidéo à une résolution de 576×1024 Pixels.
  • -b:v 1500k: Définit le débit vidéo sur 1500 kbps.

WebM est choisi comme format de sortie, car ils sont plus petits et optimisés mais largement compatibles avec la plupart des navigateurs Web.

Générer un fichier MPD manifeste

Combinez les interprétations vidéo et la piste audio dans un fichier MPD MPD conforme à Dash en exécutant le script suivant:

ffmpeg \
  -f webm_dash_manifest -i "input_video_576x1024_1500k.webm" \
  -f webm_dash_manifest -i "input_video_480x854_1000k.webm" \
  -f webm_dash_manifest -i "input_video_360x640_750k.webm" \
  -f webm_dash_manifest -i "audio.webm" \
  -c copy \
  -map 0 -map 1 -map 2 -map 3 \
  -f webm_dash_manifest \
  -adaptation_sets "id=0,streams=0,1,2 id=1,streams=3" \
  "input_video_manifest.mpd"
  • -f webm_dash_manifest -i "…": Spécifie les entrées afin que le lecteur vidéo Ash bascule entre eux en fonction des conditions de réseau.
  • -map 0 -map 1 -map 2 -map 3: Comprend toutes les vidéos (0, 1, 2) et audio (3) dans le manifeste final.
  • -adaptation_sets: Les groupes diffusent dans les ensembles d’adaptation:
    • id=0,streams=0,1,2: Groupe les interprétations vidéo en un seul ensemble d’adaptation.
    • id=1,streams=3: Attribue la piste audio à un ensemble d’adaptation séparé.

Le fichier MPD résultant (input_video_manifest.mpd) décrit les flux et permet le streaming de débit binaire adaptatif dans MPEG-Dash.

<?xml version="1.0" encoding="UTF-8"?>
<MPD
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="urn:mpeg:DASH:schema:MPD:2011"
  xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
  type="static"
  mediaPresentationDuration="PT81.166S"
  minBufferTime="PT1S"
  profiles="urn:mpeg:dash:profile:webm-on-demand:2012">

  <Period id="0" start="PT0S" duration="PT81.166S">
    <AdaptationSet
      id="0"
      mimeType="video/webm"
      codecs="vp9"
      lang="eng"
      bitstreamSwitching="true"
      subsegmentAlignment="false"
      subsegmentStartsWithSAP="1">
      
      <Representation id="0" bandwidth="1647920" width="576" height="1024">
        <BaseURL>input_video_576x1024_1500k.webm</BaseURL>
        <SegmentBase indexRange="16931581-16931910">
          <Initialization range="0-645" />
        </SegmentBase>
      </Representation>
      
      <Representation id="1" bandwidth="1126977" width="480" height="854">
        <BaseURL>input_video_480x854_1000k.webm</BaseURL>
        <SegmentBase indexRange="11583599-11583986">
          <Initialization range="0-645" />
        </SegmentBase>
      </Representation>
      
      <Representation id="2" bandwidth="843267" width="360" height="640">
        <BaseURL>input_video_360x640_750k.webm</BaseURL>
        <SegmentBase indexRange="8668326-8668713">
          <Initialization range="0-645" />
        </SegmentBase>
      </Representation>
      
    </AdaptationSet>
    
    <AdaptationSet
      id="1"
      mimeType="audio/webm"
      codecs="vorbis"
      lang="eng"
      audioSamplingRate="44100"
      bitstreamSwitching="true"
      subsegmentAlignment="true"
      subsegmentStartsWithSAP="1">
      
      <Representation id="3" bandwidth="89219">
        <BaseURL>audio.webm</BaseURL>
        <SegmentBase indexRange="921727-922055">
          <Initialization range="0-4889" />
        </SegmentBase>
      </Representation>
      
    </AdaptationSet>
  </Period>
</MPD>

Après avoir terminé ces étapes, vous aurez:

  1. Trois interprétations vidéo (576x1024, 480x854, 360x640),
  2. Une piste audio, et
  3. Un fichier MPD manifeste.
input_video.mp4
audio.webm
input_video_576x1024_1500k.webm
input_video_480x854_1000k.webm
input_video_360x640_750k.webm
input_video_manifest.mpd

La vidéo originale input_video.mp4 devrait également être maintenu pour servir de source vidéo de secours plus tard.

Servir les fichiers de sortie

Ces fichiers de sortie peuvent désormais être téléchargés sur Cloud Storage (par exemple, AWS S3 ou CloudFlare R2) pour la lecture. Bien qu’ils puissent être servis directement à partir d’un dossier local, je recommande fortement de les stocker dans le stockage cloud et de tirer parti d’un CDN pour mettre les actifs pour mettre les actifs pour de meilleures performances. AWS et CloudFlare prennent en charge les demandes de plage HTTP hors de la boîte.

Construire le lecteur vidéo compatible avec Dash en réaction

Il n’y a rien de tel qu’un exemple réel pour aider à comprendre comment tout fonctionne. Il existe différentes façons de mettre en œuvre un lecteur vidéo compatible Dash, mais je me concentrerai sur une approche à l’aide de React.

Tout d’abord, installez le Dash.js Package NPM en fonctionnant:

npm i dashjs

Ensuite, créez un composant appelé <DashVideoPlayer /> et initialiser le tableau de bord Lecteur multimédia Instance en le pointant vers le fichier MPD lorsque le composant monte.

La fonction de rappel REF s’exécute sur le montage des composants et dans la fonction de rappel, playerRef se référera au tableau de bord réel Lecteur multimédia Instance et être lié avec les auditeurs d’événements. Nous incluons également l’URL MP4 d’origine dans le <source> élément comme une secours si le navigateur ne prend pas en charge MPEG-Dash.

Si vous utilisez Routeur de l’application suivante Next.jsn’oubliez pas d’ajouter le ‘use client’ Directive pour activer l’hydratation côté client, car le lecteur vidéo n’est initialisé que du côté client.

Voici l’exemple complet:

import dashjs from 'dashjs'
import { useCallback, useRef } from 'react'

export const DashVideoPlayer = () => {
  const playerRef = useRef()

  const callbackRef = useCallback((node) => {
    if (node !== null) {  
      playerRef.current = dashjs.MediaPlayer().create()

      playerRef.current.initialize(node, "https://example.com/uri/to/input_video_manifest.mpd", false)
  
      playerRef.current.on('canPlay', () => {
        // upon video is playable
      })
  
      playerRef.current.on('error', (e) => {
        // handle error
      })
  
      playerRef.current.on('playbackStarted', () => {
        // handle playback started
      })
  
      playerRef.current.on('playbackPaused', () => {
        // handle playback paused
      })
  
      playerRef.current.on('playbackWaiting', () => {
        // handle playback buffering
      })
    }
  },[])

  return (
    <video ref={callbackRef} width={310} height={548} controls>
      <source src="https://example.com/uri/to/input_video.mp4" type="video/mp4" />
      Your browser does not support the video tag.
    </video>
  )
}

Résultat

Observez les modifications du fichier vidéo lorsque la connectivité réseau est ajustée de la 4G rapide à la 3G à l’aide de Chrome Devtools. Il passe de 480p à 360p, montrant comment l’expérience est optimisée pour une bande passante plus ou moins disponible.

Exemple ABR

Conclusion

C’est ça! Nous venons d’implémenter un lecteur vidéo compatible Dash Working dans React pour établir une vidéo avec un streaming de débit binaire adaptatif. Encore une fois, les avantages de cela sont enracinés dans performance. Lorsque nous adoptons le streaming ABR, nous demandons la vidéo en petits morceaux, permettant une lecture plus immédiate que si nous devions d’abord télécharger le fichier vidéo entièrement. Et nous l’avons fait d’une manière qui prend en charge plusieurs versions de la même vidéo, nous permettant de servir le meilleur format pour l’appareil de l’utilisateur.

Références

Smashing Editorial
(GG, YK)




Source link