Enregistrement de la vidéo de l'utilisateur

Balances à tapis

De nombreux navigateurs ont désormais la possibilité d'accéder aux entrées audio et vidéo 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.

Procédez de manière simple et progressive

Le plus simple est de demander simplement à 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 des 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, elle ouvre l'application Appareil photo, ce qui vous permet d'enregistrer une vidéo, puis de la renvoyer vers la page Web. Sous Android, elle permet à l'utilisateur de choisir l'application dans laquelle enregistrer la vidéo avant de la renvoyer vers la page Web.

De nombreux appareils mobiles intègrent 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 voulez que la caméra soit orientée vers l'extérieur.

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

Notez qu'il s'agit seulement d'un indice : si le navigateur n'est pas compatible avec cette option ou si le type de caméra que vous demandez n'est pas disponible, le navigateur peut sélectionner 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 é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 bon vous semble. Par exemple, vous pouvez :

  • l'associer directement à un élément <video> pour pouvoir le lire ;
  • Le télécharger sur l'appareil de l'utilisateur
  • L'importer sur un serveur en l'associant à un XMLHttpRequest
  • Dessiner les cadres sur un canevas et y appliquer des filtres

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

Accéder à l'appareil photo de manière interactive

Les navigateurs récents peuvent être reliés directement à 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ès à l'appareil photo

Nous pouvons accéder directement à l'appareil photo à l'aide d'une API dans la spécification WebRTC, appelée getUserMedia(). getUserMedia() demandera à l'utilisateur d'accéder à ses micros et appareils photo connectés.

Si l'opération réussit, l'API renvoie un Stream contenant 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 l'appareil photo, 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 en particulier, commencez par énumérer les caméras disponibles.

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

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

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

En soi, ce n’est pas très utile. Tout ce que nous pouvons faire, c'est prendre les données de la vidéo et les lire.

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

Pour accéder aux données vidéo brutes de l'appareil photo, 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 le cadre 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, l'image actuelle de la vidéo en cours de lecture est 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 la caméra

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 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 le cas présent, nous enregistrons les données directement dans un tableau que nous pouvons ensuite transformer en Blob, qui peut ensuite être utilisé pour l'enregistrement 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 déjà autorisé votre site à accéder à l'appareil photo, dès que vous appelez getUserMedia, le navigateur l'invite à autoriser votre site à y accéder.

L'utilisateur déteste être invité à accéder à des appareils puissants sur sa machine. Il bloquera fréquemment la requête ou l'ignorera s'il ne comprend pas le contexte dans lequel l'invite a été créée. Il est recommandé de ne demander à accéder à l'appareil photo qu'en cas de besoin. 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 pas le récupérer pour demander l'autorisation à l'utilisateur.

Utilisez l'API Permissions pour vérifier si vous avez déjà accès

L'API getUserMedia ne vous indique pas si vous avez déjà accès à la caméra. Cela pose problème. Pour que l'interface utilisateur puisse vous inciter à accéder à l'appareil photo, vous devez demander l'accès à l'appareil photo.

Dans certains navigateurs, le problème peut être résolu à l'aide de l'API Permission. L'API navigator.permission vous permet d'interroger l'état de la capacité d'accès à des API spécifiques sans avoir à relancer la requête.

Pour demander si vous avez accès à l'appareil photo de l'utilisateur, vous pouvez transmettre {name: 'camera'} à la méthode de requête. Celle-ci renvoie alors l'un des éléments suivants:

  • granted : l'utilisateur vous a précédemment autorisé à accéder à l'appareil photo.
  • prompt : l'utilisateur ne vous a pas accordé l'accès et sera invité à appeler getUserMedia.
  • denied : le système ou l'utilisateur a explicitement bloqué l'accès à la caméra, 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