Enregistrement de la vidéo de l'utilisateur

Mat Scales

De nombreux navigateurs peuvent désormais accéder aux entrées vidéo et audio de l'utilisateur. Toutefois, selon le navigateur, il peut s'agir d'une expérience dynamique et intégrée complète, ou elle peut être déléguée à une autre application sur l'appareil de l'utilisateur.

Commencez simplement et progressivement

Le plus simple est de demander à l'utilisateur un fichier préenregistré. Pour ce faire, créez un élément d'entrée de fichier simple et ajoutez un filtre accept qui indique que nous ne pouvons accepter que les fichiers vidéo et un attribut capture qui indique que nous voulons l'obtenir directement depuis l'appareil photo.

<input type="file" accept="video/*" capture />

Cette méthode fonctionne sur toutes les plates-formes. Sur ordinateur, l'utilisateur est invité à importer un fichier à partir du système de fichiers (en ignorant l'attribut capture). Dans Safari sur iOS, l'application Appareil photo s'ouvre, ce qui vous permet d'enregistrer une vidéo, puis de la renvoyer vers la page Web. Sur Android, l'utilisateur peut choisir l'application à utiliser pour enregistrer la vidéo avant de la renvoyer vers la page Web.

De nombreux appareils mobiles sont équipés de plusieurs caméras. Si vous avez une préférence, vous pouvez définir l'attribut capture sur user si vous souhaitez utiliser la caméra orientée vers l'utilisateur, ou sur environment si vous souhaitez utiliser la caméra orientée vers l'extérieur.

<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />

Notez qu'il ne s'agit que d'une indication. Si le navigateur n'est pas compatible avec l'option ou si le type de caméra que vous demandez n'est pas disponible, le navigateur peut choisir une autre caméra.

Une fois que l'utilisateur a terminé l'enregistrement et qu'il est de retour sur le site Web, vous devez récupérer les données du fichier. Vous pouvez y accéder rapidement en associant un événement onchange à l'élément d'entrée, puis en lisant la propriété files de l'objet d'événement.

<input type="file" accept="video/*" capture="camera" id="recorder" />
<video id="player" controls></video>
<script>
  var recorder = document.getElementById('recorder');
  var player = document.getElementById('player');

  recorder.addEventListener('change', function (e) {
    var file = e.target.files[0];
    // Do something with the video file.
    player.src = URL.createObjectURL(file);
  });
</script>

Une fois que vous avez accès au fichier, vous pouvez en faire ce que vous voulez. Par exemple, vous pouvez :

  • Associez-le directement à un élément <video> pour pouvoir le lire.
  • Téléchargez-le sur l'appareil de l'utilisateur.
  • Importez-le sur un serveur en l'associant à un XMLHttpRequest.
  • Dessiner les images dans un canevas et lui appliquer des filtres

Bien que l'utilisation de la méthode de l'élément d'entrée pour accéder aux données vidéo soit omniprésente, c'est l'option la moins attrayante. Nous voulons vraiment accéder à l'appareil photo et offrir une expérience agréable directement sur la page.

Accéder à la caméra de manière interactive

Les navigateurs récents peuvent avoir une ligne directe vers l'appareil photo, ce qui nous permet de créer des expériences entièrement intégrées à la page Web, sans que l'utilisateur n'ait à quitter le navigateur.

Obtenir l'accès à l'appareil photo

Nous pouvons accéder directement à la caméra en utilisant une API de la spécification WebRTC appelée getUserMedia(). getUserMedia() demandera à l'utilisateur l'accès à ses micros et caméras connectés.

Si l'opération réussit, l'API renvoie un Stream qui contient les données de la caméra ou du micro. Nous pouvons ensuite l'associer à un élément <video>, l'associer à un flux WebRTC ou l'enregistrer à l'aide de l'API MediaRecorder.

Pour obtenir des données de la caméra, nous définissons simplement video: true dans l'objet de contraintes transmis à l'API getUserMedia().

<video id="player" controls></video>
<script>
  var player = document.getElementById('player');

  var handleSuccess = function (stream) {
    player.srcObject = stream;
  };

  navigator.mediaDevices
    .getUserMedia({audio: true, video: true})
    .then(handleSuccess);
</script>

Si vous souhaitez choisir une caméra en particulier, vous pouvez d'abord énumérer les caméras disponibles.

navigator.mediaDevices.enumerateDevices().then((devices) => {
  devices = devices.filter((d) => d.kind === 'videoinput');
});

Vous pouvez ensuite transmettre le deviceId que vous souhaitez utiliser lorsque vous appelez getUserMedia.

navigator.mediaDevices.getUserMedia({
  audio: true,
  video: {
    deviceId: devices[0].deviceId,
  },
});

En soi, cela n'est pas très utile. Tout ce que nous pouvons faire, c'est récupérer les données vidéo et les lire.

Accéder aux données brutes de la caméra

Pour accéder aux données vidéo brutes de la caméra, vous pouvez dessiner chaque image dans un <canvas> et manipuler les pixels directement.

Pour un canevas 2D, vous pouvez utiliser la méthode drawImage du contexte pour dessiner l'image actuelle d'un élément <video> dans le canevas.

context.drawImage(myVideoElement, 0, 0);

Avec un canevas WebGL, vous pouvez utiliser un élément <video> comme source d'une texture.

gl.texImage2D(
  gl.TEXTURE_2D,
  0,
  gl.RGBA,
  gl.RGBA,
  gl.UNSIGNED_BYTE,
  myVideoElement,
);

Notez que, dans les deux cas, l'image actuelle d'une vidéo en cours de lecture sera utilisée. Pour traiter plusieurs images, vous devez redessiner la vidéo sur le canevas à chaque fois.

Pour en savoir plus, consultez notre article sur l'application d'effets en temps réel aux images et aux vidéos.

Enregistrer les données de l'appareil photo

Le moyen le plus simple d'enregistrer les données de l'appareil photo consiste à utiliser l'API MediaRecorder.

L'API MediaRecorder prendra le flux créé par getUserMedia, puis enregistrera progressivement les données du flux vers la destination de votre choix.

<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
  let shouldStop = false;
  let stopped = false;
  const downloadLink = document.getElementById('download');
  const stopButton = document.getElementById('stop');

  stopButton.addEventListener('click', function() {
    shouldStop = true;
  })

  var handleSuccess = function(stream) {
    const options = {mimeType: 'video/webm'};
    const recordedChunks = [];
    const mediaRecorder = new MediaRecorder(stream, options);

    mediaRecorder.addEventListener('dataavailable', function(e) {
      if (e.data.size > 0) {
        recordedChunks.push(e.data);
      }

      if(shouldStop === true && stopped === false) {
        mediaRecorder.stop();
        stopped = true;
      }
    });

    mediaRecorder.addEventListener('stop', function() {
      downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
      downloadLink.download = 'acetest.webm';
    });

    mediaRecorder.start();
  };

  navigator.mediaDevices.getUserMedia({ audio: true, video: true })
      .then(handleSuccess);
</script>

Dans notre cas, nous enregistrons les données directement dans un tableau que nous pouvons ensuite transformer en Blob, qui peut ensuite être utilisé pour enregistrer sur notre serveur Web ou directement dans l'espace de stockage de l'appareil de l'utilisateur.

Demander l'autorisation d'utiliser l'appareil photo de manière responsable

Si l'utilisateur n'a pas encore autorisé votre site à accéder à l'appareil photo, le navigateur l'invite à le faire dès que vous appelez getUserMedia.

Les utilisateurs n'aiment pas être invités à accéder à des appareils puissants sur leur machine. Ils bloquent souvent la demande ou l'ignorent s'ils ne comprennent pas le contexte dans lequel l'invite a été créée. Il est recommandé de ne demander l'accès à l'appareil photo que lorsque cela est nécessaire pour la première fois. Une fois que l'utilisateur a accordé l'accès, il n'est plus invité à le faire. Toutefois, s'il refuse l'accès, vous ne pouvez plus lui demander l'autorisation.

Utiliser l'API Permissions pour vérifier si vous disposez déjà d'un accès

L'API getUserMedia ne vous indique pas si vous avez déjà accès à l'appareil photo. Cela vous pose un problème : pour fournir une interface utilisateur agréable permettant à l'utilisateur de vous accorder l'accès à l'appareil photo, vous devez demander l'accès à l'appareil photo.

Dans certains navigateurs, ce problème peut être résolu à l'aide de l'API Permission. L'API navigator.permission vous permet d'interroger l'état de la possibilité d'accéder à des API spécifiques sans avoir à demander à nouveau l'autorisation.

Pour savoir si vous avez accès à l'appareil photo de l'utilisateur, vous pouvez transmettre {name: 'camera'} à la méthode de requête, qui renverra l'un des éléments suivants :

  • granted : l'utilisateur vous a déjà autorisé à accéder à l'appareil photo.
  • prompt : l'utilisateur ne vous a pas accordé l'accès et sera invité à le faire lorsque vous appellerez getUserMedia.
  • denied : le système ou l'utilisateur a explicitement bloqué l'accès à l'appareil photo, et vous ne pourrez pas y accéder.

Vous pouvez maintenant vérifier rapidement si vous devez modifier votre interface utilisateur pour l'adapter aux actions que l'utilisateur doit effectuer.

navigator.permissions.query({name: 'camera'}).then(function (result) {
  if (result.state == 'granted') {
  } else if (result.state == 'prompt') {
  } else if (result.state == 'denied') {
  }
  result.onchange = function () {};
});

Commentaires