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 entièrement dynamique et intégrée, ou d'une délégation à une autre application sur l'appareil de l'utilisateur.

La méthode la plus simple consiste à demander à l'utilisateur de fournir un fichier préenregistré. Pour ce faire, créez un élément d'entrée de fichier simple et ajoutez un filtre accept indiquant que nous ne pouvons accepter que des fichiers vidéo et un attribut capture indiquant que nous souhaitons l'obtenir directement depuis la caméra.

<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 (l'attribut capture étant ignoré). Dans Safari sur iOS, l'application Appareil photo s'ouvre, ce qui vous permet d'enregistrer une vidéo, puis de la renvoyer sur la page Web. Sur Android, l'utilisateur peut choisir l'application dans laquelle enregistrer la vidéo avant de la renvoyer sur 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 que la caméra soit orientée vers l'utilisateur ou sur environment si vous souhaitez qu'elle soit 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'un indice. Si le navigateur n'est pas compatible avec l'option ou si le type de caméra que vous demandez n'est pas disponible, il 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. Pour obtenir un accès rapide, associez un événement onchange à l'élément d'entrée, puis lisez la propriété files de l'objet é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 l'utiliser comme vous le souhaitez. Par exemple, vous pouvez :

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

Même si l'utilisation de l'élément d'entrée pour accéder aux données vidéo est omniprésente, il s'agit de l'option la moins attrayante. Nous souhaitons 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 ne quitte le navigateur.

Accéder à l'appareil photo

Nous pouvons accéder directement à la caméra à l'aide d'une API de la spécification WebRTC appelée getUserMedia(). getUserMedia() demandera à l'utilisateur d'accéder à 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, il suffit de définir 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 spécifique, 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 l'identifiant de l'appareil que vous souhaitez utiliser lorsque vous appelez getUserMedia.

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

Cela n'est pas très utile en soi. Tout ce que nous pouvons faire est de récupérer les données vidéo et de les lire.

Accéder aux données brutes de l'appareil photo

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

Pour un canevas 2D, vous pouvez utiliser la méthode drawImage du contexte pour dessiner le frame actuel 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, le cadre actuel d'une vidéo en cours de lecture sera utilisé. 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 récupère le flux créé par getUserMedia, puis enregistre progressivement les données du flux à 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 convertir 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 la caméra de manière responsable

Si l'utilisateur n'a pas encore autorisé votre site à accéder à l'appareil photo, l'instant où vous appelez getUserMedia, le navigateur invitera l'utilisateur à autoriser votre site à accéder à l'appareil photo.

Les utilisateurs détestent être invités à accéder à des appareils puissants sur leur ordinateur. Ils bloquent souvent la requête 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 à la caméra que lorsque vous en avez besoin 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 pourrez pas obtenir à nouveau l'accès pour lui demander l'autorisation.

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

L'API getUserMedia ne vous permet pas de savoir si vous avez déjà accès à l'appareil photo. Cela pose un problème. Pour fournir une UI attrayante pour que l'utilisateur vous autorise à accéder à la caméra, vous devez demander l'accès à la caméra.

Pour résoudre ce problème dans certains navigateurs, vous pouvez utiliser 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.

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

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

Vous pouvez désormais vérifier rapidement si vous devez modifier votre interface utilisateur pour tenir compte des 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