Audio & vidéo

Les éléments <audio> et <video> ont une API qui permet de contrôler la lecture/pause, etc.

Rappel HTML

Video

L’élément <video> permet d’intégrer des vidéos dans une page web. Du contenu alternatif peut être placé dans cette balise, il sera affiché si la navigateur ne prend pas en charge cet élément.

<video src="rabbit320.webm" controls>
  <p>Votre navigateur ne prend pas en charge les vidéos HTML5.
  Voici, à la place, un <a href="rabbit320.webm">lien sur la vidéo</a>.</p> 
</video>

Différents formats vidéos peuvent être utilisés: webm, mp4 ou off. Tous les navigateurs ne prennent pas en charge les mêmes codecs - les navigateurs ne détenant pas les droits du format (brevet) doivent acheter une licence, qui coûte parfois très cher.

Pour pallier à ça, plutôt que de spécifier src, vous pouvez spécifier plusieurs <source> à l’intérieur, le navigateur affichera la premiière vidéo qu’il peut prendre en charge.

<video controls>
  <source src="rabbit320.mp4" type="video/mp4">
  <source src="rabbit320.webm" type="video/webm">
  <p>Votre navigateur ne supporte pas la vidéo HTML5.
  Voici à la place <a href="rabbit320.mp4">un lien vers la vidéo</a>.</p>
</video>

Attributs

width, height dimensions du lecteur
controls afficher les contrôles natifs du lecteur vidéo
crossorigin anonymous = envoie une requête CORS avec l'entête HTTP Origin
use-credentials = envoie une requête CORS avec l'entête HTTP Header
Si l'attribut n'est pas définit, la ressource est récupérée sans requête CORS
autoplay lancer la lecture de la vidéo dès qu’elle est chargée
loop lire en boucle
muted mettre en sourdine par défaut
poster image affichée avant que la lecture ne soit lancée
preload indique au navigateur s’il doit charger la vidéo en même temps que la page (par défaut: metadata)
src définit la source du média. Sinon, on peut utiliser des éléments <source> (l'un ou l'autre)
type si la source est définit via src, définit son type MIME
<video controls width="400" height="400"
       autoplay loop muted
       poster="poster.png">

Audio

L’élément <audio> fonctionne de la même manière que <video> mais pour les éléments audio. Les formats audio pouvant être acceptés sont: mp3, wav, ogg.

<audio controls>
  <source src="viper.mp3" type="audio/mp3">
  <source src="viper.ogg" type="audio/ogg">
  <p>Votre navigateur ne prend pas en charge l'audio HTML5.
  Voici, à la place, un <a href="viper.mp3">lien sur l'audio</a>.</p>
</audio>

Attributs: les mêmes que vidéo sauf width, height et poster.

Track

Les vidéos HTML peuvent être sous-titrée à l’aide du format WebVTT et de l’élément <track>.

WebVTT est un format d’écriture de fichier texte .vtt, il contient des chaînes de texte et des metadatas (temps et durée des sous-titres, style et position). Un fichier WebVTT typique ressemblera à ça:

WEBVTT

1
00:00:22.230 --> 00:00:24.606
Ceci est le premier sous‑titre.

2
00:00:30.739 --> 00:00:34.074
Ceci est le deuxième.

Les éléments <track> permettent d’attacher des fichiers WebVTT à la vidéo. On précise son type avec kind (subtitles, captions ou descriptions), son emplacement avec src et son langage avec srclang.

<video controls>
    <source src="example.mp4" type="video/mp4">
    <source src="example.webm" type="video/webm">
    <track label="English" kind="subtitles" srclang="en" src="captions/vtt/sintel-en.vtt" default>
    <track label="Deutsch" kind="subtitles" srclang="de" src="captions/vtt/sintel-de.vtt">
    <track label="Español" kind="subtitles" srclang="es" src="captions/vtt/sintel-es.vtt">
</video>

NB Si vos sous-titres sont au format SubRip Text (SRT), vous pouvez facilement les convertir au format WebVTT.
Les pistes texte sont utiles pour les personnes malentendantes ou qui parlent une langue étrangère mais aussi pour les moteurs de recherche.

Fallback

Pour les navigateurs qui ne prennent pas en charge les balises <audio> et <video>, on peut utiliser mediaelement.js.

<video width="320" height="240" poster="poster.jpg" controls="controls" preload="none">
  <source type="video/mp4" src="myvideo.mp4" />
  <source type="video/webm" src="myvideo.webm" />
  <source type="video/ogg" src="myvideo.ogv" />
  <object width="320" height="240" type="application/x-shockwave-flash" data="/path/to/mediaelement-flash-video.swf">
    <param name="movie" value="/path/to/mediaelement-flash-video.swf" />
    <param name="flashvars" value="controls=true&amp;poster=myvideo.jpg&amp;file=myvideo.mp4" />
    <img src="myvideo.jpg" width="320" height="240" title="No video playback capabilities" />
  </object>
</video>

Créer les éléments via JavaScript

Audio

var myAudio = document.createElement('audio');

if (myAudio.canPlayType('audio/mpeg')) {
    myAudio.setAttribute('src', 'audiofile.mp3');
} else if (myAudio.canPlayType('audio/ogg')) {
    myAudio.setAttribute('src', 'audiofile.ogg');
}

myAudio.currentTime = 5;
myAudio.play();

Vidéo

var myVideo = document.createElement('video');

if (myVideo.canPlayType('video/mp4')) {
  myVideo.setAttribute('src','videofile.mp4');
} else if (myVideo.canPlayType('video/webm')) {
  myVideo.setAttribute('src','videofile.webm');
}

myVideo.width = 480;
myVideo.height = 320;

Contrôles personnalisés

Les contrôles audio et vidéo natifs différent d’un navigateur à l’autre et sont généralement assez peu accessibles au clavier. Pour régler ce problème, on peut masquer les contrôles natifs et afficher les notres, en utilisant l’API HTMLMediaElement côté JavaScript pour déclencher les actions de l’utilisateur.

Les éléments <audio> et <video> utilisent tous deux l’API HTMLMediaElement, la seule différence entre les deux est qu’un élément audio n’a pas de visuel.

Exemple lecteur personnalisé
Exemple 2

Afficher les contrôles personnalisés

Le mieux à faire est

Play/pause

On peut utiliser la propriété paused pour savoir si la vidéo est en cours de lecture ou non et les méthodes play() et pause() pour lire ou mettre en pause la vidéo (respectivement).

playBtn.addEventListener('click', playPauseMedia);

function playPauseMedia() {
  if(media.paused || media.ended) {
    media.play();
  } else {
    media.pause();
  }
}

Stop

Il n’y a pas de méthode stop(), mais on peut obtenir cet effet en appelant pause() puis en mettant currentTime à 0.

stopBtn.addEventListener('click', stopMedia);
media.addEventListener('click', stopMedia);

function stopMedia() {
  media.pause();
  media.currentTime = 0;
}

Temps écoulé

L’événement timeupdate est déclenché régulièrement tant que la vidéo est en cours, on peut s’en servir pour mettre à jour l’affichage du temps écoulé. La fréquence à laquelle cet événement est déclenché dépend entre autres de votre navigateur et de la puissance de votre CPU.

Vous pouvez utiliser la propriété currentTime pour déterminer la position actuelle de l’utilisateur dans la vidéo (en secondes) ou la mettre à jour. La propriété duration quant à elle permet de déterminer la durée totale de la vidéo, en secondes.

media.addEventListener('timeupdate', setTime);

function setTime() {
  var minutes = Math.floor(media.currentTime / 60);
  var seconds = Math.floor(media.currentTime - minutes * 60);

  // Afficher le temps écoulé
  timer.textContent = minutes.padStart(2, "0") + ':' + seconds.padStart(2, "0");

  // Afficher la progressbar
  var barLength = timerWrapper.clientWidth * (media.currentTime / media.duration);
  timerBar.style.width = barLength + 'px';
}

Volume

Le volume de la vidéo (ou audio) peut être récupéré ou mis à jour avec la propriété volume.
1 = volume maximal (valeur par défaut), 0 = muet.

soundRange.addEventListener("change", changeVolume);

function changeVolume(e) {
  media.volume = e.target.value;
}

Vous pouvez utiliser la propriété muted pour mettre en sourdine l’élément et l’événement onvolumechange pour détecter les changements de volume.

Vitesse de lecture

La vitesse de lecture est accessible via la propriété playbackRate.
2 = deux fois plus rapide, 0.5 = deux fois plus lent.

rateRange.addEventListener("change", changeRate);

function changeRate(e) {
  media.playbackRate = e.target.value;
}

La vitesse de lecture par défaut peut être définie avec la propriété defaultPlaybackRate. Cela permet de définir la vitesse de lecture de la vidéo avant qu’elle soit chargée.

L’événement ratechange est déclenché à chaque changement de vitesse de lecture.

Plein écran

Vous pouvez au préalable si le navigateur prend en charge l’API Fullscreen:

var fullScreenEnabled = !!(document.fullscreenEnabled || document.mozFullScreenEnabled
                            || document.msFullscreenEnabled || document.webkitSupportsFullscreen
                            || document.webkitFullscreenEnabled || media.webkitRequestFullScreen);

Et l’appeler quand l’utilisateur clic sur le bouton plein écran:

if(fullScreenEnabled) {
  fullscreenBtn.style.display = "inline-block";
  fullscreenBtn.addEventListener("click", openFullscreen);
}

function openFullscreen() {
  if (media.requestFullscreen) {
    media.requestFullscreen();
  } else if (media.msRequestFullscreen) {
    media.msRequestFullscreen();
  } else if (media.mozRequestFullScreen) {
    media.mozRequestFullScreen();
  } else if (media.webkitRequestFullscreen) {
    media.webkitRequestFullscreen();
  }
}

Légendes et sous-titres

La propriété textTracks contient un tableau de tous les éléments <track> attachés à la vidéo. On peut les désactiver en mettant leur mode à hidden ou en activer un en mettant son code à showing.

// Désactiver tous les sous-titres
for(var i = 0; i < media.textTracks.length; i++) {
  media.textTracks[i].mode = 'hidden';
}
// Activer la première piste de sous-titres
media.textTracks[0].mode = "showing";

NB Il est nécessaire d’utiliser CORS lorsque vos fichiers CC ne se trouvent pas sur le même domaine que la page hébergeant l’élément audio/video. Pour que cela fonctionne, il est nécessaire d’ajouter l’attribut crossorigin à l’élement audio/video.

<video ... crossorigin="anonymous">

CSS

Du CSS peut être appliqué aux sous-titres via le pseudo-élément ::cue.

::cue {
   color: #ccc;
}

Un fichier WebVTT peut spécifier des “voix”:

0
00:00:00.000 --> 00:00:12.000
<v Test>[Test]</v>

Du CSS peut être appliqué en ciblant ces voix comme suit:

::cue(v[voice='Test']) {
   color:#fff;
   background:#0095dd;
}

Chargement

buffered

La propriété buffered permet de savoir quelles parties du média sont en mémoire tamppon. À priori, sans interraction utilisateur, la partie mise en mémoire tampon en contigue. Par contre, en cliquant sur la barre de progrès pendant que le média est en cours de chargement pour écouter le média plus loin, plusieurs parties peuvent être chargées, avec des trous entre les deux.

buffered retourne un objet TimeRanges. Il contient les propriétés/méthodes suivantes:

lengthle nombre de plages de temps contenues dans l'objet
start(index)permet de récupérer le temps du début (en seconde) d'une plage de temps
end(index)permet de récupérer le temps de la fin (en seconde) d'une plage de temps

L’événement progress est déclenché au fur et à mesure que les données sont téléchargées, cela peut nous permettre par exemple d’afficher une barre de progrès du chargement de la vidéo.

JSBin Barre de progrès mémoire tampon

seekable

La propriété seekable permet de savoir quelles parties du média peuvent être jouées sans chargement préalable.
Elle retourne un TimeRanges.

La valeur retournée est différente de buffered lorsque le téléchargement de plages d’octets (byte-range requests) est activé sur le serveur. Les requêtes de plage d’octets permettent aux parties du fichier média d’être délivrées du serveur et jouées presque immédiatement — et sont donc seekable.

played

La propriété played permet de savoir quelles plages de temps de la vidéo ont été jouées. Elle retourne un TimeRanges.
Cela peut être utile si vous voulez savoir quelles parties d’une vidéo ont été visualisées par exemple.


Pour aller plus loin