Registrazione di un video dell'utente

Mat Scales

Molti browser ora hanno la possibilità di accedere all'input video e audio dell'utente. Tuttavia, a seconda del browser, potrebbe trattarsi di un'esperienza completamente dinamica e in linea oppure potrebbe essere delegata a un'altra app sul dispositivo dell'utente.

Inizia con una configurazione semplice e aumenta il livello

La cosa più semplice da fare è chiedere all'utente un file preregistrato. Per farlo, crea un semplice elemento di input file e aggiungi un filtro accept che indica che possiamo accettare solo file video e un attributo capture che indica che vogliamo acquisirli direttamente dalla fotocamera.

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

Questo metodo funziona su tutte le piattaforme. Su computer, all'utente verrà chiesto di caricare un file dal file system (ignorando l'attributo capture). In Safari su iOS, si aprirà l'app Fotocamera, che ti consentirà di registrare un video e poi inviarlo alla pagina web. Su Android, l'utente potrà scegliere quale app utilizzare per registrare il video prima di inviarlo alla pagina web.

Molti dispositivi mobili hanno più di una fotocamera. Se hai una preferenza, puoi impostare l'attributo capture su user, se vuoi la fotocamera rivolta verso l'utente, o su environment se vuoi la fotocamera rivolta verso l'esterno.

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

Tieni presente che si tratta solo di un suggerimento: se il browser non supporta l'opzione o il tipo di fotocamera che richiedi non è disponibile, il browser potrebbe scegliere un'altra fotocamera.

Una volta che l'utente ha terminato la registrazione ed è tornato al sito web, devi in qualche modo recuperare i dati del file. Puoi ottenere un accesso rapido collegando un evento onchange all'elemento di input e poi leggendo la proprietà files dell'oggetto evento.

<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>

Una volta ottenuto l'accesso al file, puoi farci tutto ciò che vuoi. Ad esempio, puoi:

  • Collegalo direttamente a un elemento <video> per poterlo riprodurre
  • Scaricalo sul dispositivo dell'utente
  • Caricalo su un server collegandolo a un XMLHttpRequest
  • Disegna i frame in un canvas e applica i filtri

Sebbene l'utilizzo del metodo dell'elemento di input per accedere ai dati video sia molto diffuso, è l'opzione meno interessante. Vogliamo davvero ottenere l'accesso alla fotocamera e offrire un'esperienza piacevole direttamente nella pagina.

Accedi alla fotocamera in modo interattivo

I browser moderni possono avere una linea diretta con la fotocamera, il che ci consente di creare esperienze completamente integrate con la pagina web e l'utente non lascerà mai il browser.

Acquisire l'accesso alla fotocamera

Possiamo accedere direttamente alla fotocamera utilizzando un'API nella specifica WebRTC chiamata getUserMedia(). getUserMedia() chiederà all'utente l'accesso ai microfoni e alle videocamere collegati.

Se l'operazione va a buon fine, l'API restituirà un Stream che conterrà i dati della videocamera o del microfono, che potremo poi collegare a un elemento <video>, a uno stream WebRTC o salvare utilizzando l'API MediaRecorder.

Per ottenere i dati dalla fotocamera, abbiamo appena impostato video: true nell'oggetto constraints che viene passato all'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>

Se vuoi scegliere una videocamera specifica, puoi prima elencare le videocamere disponibili.

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

Puoi quindi passare il deviceId che vuoi utilizzare quando chiami getUserMedia.

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

Di per sé, questo non è molto utile. Tutto ciò che possiamo fare è acquisire i dati video e riprodurli.

Accedere ai dati non elaborati della fotocamera

Per accedere ai dati video non elaborati della videocamera, puoi disegnare ogni frame in un <canvas> e manipolare direttamente i pixel.

Per un canvas 2D, puoi utilizzare il metodo drawImage del contesto per disegnare il frame corrente di un elemento <video> nel canvas.

context.drawImage(myVideoElement, 0, 0);

Con un canvas WebGL puoi utilizzare un elemento <video> come origine per una texture.

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

Tieni presente che in entrambi i casi verrà utilizzato il frame corrente di un video in riproduzione. Per elaborare più frame, devi ridisegnare il video sul canvas ogni volta.

Per saperne di più, consulta il nostro articolo sull'applicazione di effetti in tempo reale a immagini e video.

Salva i dati della videocamera

Il modo più semplice per salvare i dati della fotocamera è utilizzare l'API MediaRecorder.

L'API MediaRecorder acquisirà lo stream creato da getUserMedia e poi salverà progressivamente i dati dello stream nella destinazione che preferisci.

<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>

Nel nostro caso, salviamo i dati direttamente in un array che possiamo poi trasformare in un Blob, che può essere utilizzato per il salvataggio sul nostro server web o direttamente nello spazio di archiviazione sul dispositivo dell'utente.

Chiedi l'autorizzazione per utilizzare la fotocamera in modo responsabile

Se l'utente non ha concesso in precedenza al tuo sito l'accesso alla fotocamera, nel momento in cui chiami getUserMedia il browser chiederà all'utente di concedere al tuo sito l'autorizzazione per la fotocamera.

Gli utenti non amano ricevere richieste di accesso a dispositivi potenti sul proprio computer e spesso bloccano la richiesta o la ignorano se non comprendono il contesto in cui è stata creata. La best practice è richiedere l'accesso alla fotocamera solo quando è necessario per la prima volta. Una volta che l'utente ha concesso l'accesso, non gli verrà più chiesto. Tuttavia, se rifiuta l'accesso, non potrai più accedere per chiedere l'autorizzazione all'utente.

Utilizza l'API Permissions per verificare se hai già l'accesso

L'API getUserMedia non ti fornisce informazioni sull'accesso alla videocamera. Questo ti pone un problema: per fornire una bella UI per convincere l'utente a concederti l'accesso alla fotocamera, devi chiedere l'accesso alla fotocamera.

In alcuni browser, questo problema può essere risolto utilizzando l'API Permission. L'API navigator.permission ti consente di eseguire query sullo stato della possibilità di accedere ad API specifiche senza dover chiedere di nuovo.

Per verificare se hai accesso alla fotocamera dell'utente, puoi passare {name: 'camera'} nel metodo di query, che restituirà:

  • granted: l'utente ti ha concesso l'accesso alla fotocamera in precedenza;
  • prompt: l'utente non ti ha concesso l'accesso e gli verrà richiesto quando chiami getUserMedia;
  • denied: il sistema o l'utente ha bloccato esplicitamente l'accesso alla fotocamera e non potrai accedervi.

Ora puoi controllare rapidamente se devi modificare l'interfaccia utente per adattarla alle azioni che l'utente deve eseguire.

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 () {};
});

Feedback