Grabación de video del usuario

Escalas para colchonetas

Muchos navegadores ahora tienen la capacidad de acceder a la entrada de audio y video del usuario. Sin embargo, según el navegador, puede ser una experiencia en línea y dinámica completa o se puede delegar a otra app en el dispositivo del usuario.

Comenzar de manera simple y progresiva

Lo más fácil es simplemente pedirle al usuario un archivo pregrabado. Para ello, crea un elemento de entrada de archivo simple y agrega un filtro accept que indique que solo podemos aceptar archivos de video y un atributo capture que indique que queremos obtenerlos directamente desde la cámara.

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

Este método funciona en todas las plataformas. En las computadoras de escritorio, se le solicitará al usuario que suba un archivo desde el sistema de archivos (sin considerar el atributo capture). En Safari para iOS, se abrirá la app de la cámara, lo que te permitirá grabar video y, luego, enviarlo de vuelta a la página web. En Android, esto le dará al usuario la opción de usar para grabar el video antes de enviarlo de vuelta a la página web.

Muchos dispositivos móviles tienen más de una cámara. Si tienes alguna preferencia, puedes establecer el atributo capture en user si quieres utilizar la cámara orientada al usuario o en environment si quieres que la cámara apunte hacia afuera.

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

Ten en cuenta que esta es solo una sugerencia. Si el navegador no admite la opción o si el tipo de cámara que solicitaste no está disponible, es posible que el navegador elija otra cámara.

Una vez que el usuario haya terminado de grabar y esté de vuelta en el sitio web, de alguna manera debes conseguir los datos del archivo. Para obtener acceso rápido, adjunta un evento onchange al elemento de entrada y, luego, lee la propiedad files del objeto del 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 vez que tengas acceso al archivo, podrás hacer lo que quieras con él. Por ejemplo, puedes hacer lo siguiente:

  • Adjúntala directamente a un elemento <video> para que puedas reproducirla
  • Descárgalo en el dispositivo del usuario
  • Para subirla a un servidor, adjúntala a un XMLHttpRequest
  • Dibuja los marcos en un lienzo y aplícales filtros

Si bien el uso del método de elemento de entrada para obtener acceso a los datos de video es universal, es la opción menos atractiva. Queremos acceder a la cámara y ofrecer una experiencia agradable directamente en la página.

Cómo acceder a la cámara de forma interactiva

Los navegadores modernos pueden tener una línea directa a la cámara, lo que nos permite crear experiencias que están completamente integradas con la página web, de modo que el usuario nunca salga del navegador.

Adquiere acceso a la cámara

Podemos acceder directamente a la cámara mediante una API en la especificación WebRTC llamada getUserMedia(). getUserMedia() le solicitará al usuario acceso a sus micrófonos y cámaras conectados.

Si se ejecuta de forma correcta, la API mostrará un Stream que contendrá los datos de la cámara o del micrófono y, luego, podremos adjuntarlo a un elemento <video>, a una transmisión de WebRTC o guardarlo con la API de MediaRecorder.

Para obtener datos de la cámara, configuramos video: true en el objeto de restricciones que se pasa a la 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 deseas elegir una cámara en particular, primero puedes enumerar las cámaras disponibles.

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

Luego, puedes pasar el deviceId que deseas usar cuando llamas a getUserMedia.

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

Por sí mismo, no es tan útil. Todo lo que podemos hacer es tomar los datos del video y reproducirlos.

Accede a los datos sin procesar de la cámara

Para acceder a los datos de video sin procesar de la cámara, puedes dibujar cada fotograma en un <canvas> y manipular los píxeles directamente.

En el caso de un lienzo 2D, puedes usar el método drawImage del contexto para dibujar el marco actual de un elemento <video> en el lienzo.

context.drawImage(myVideoElement, 0, 0);

Con un lienzo de WebGL, puedes usar un elemento <video> como fuente de una textura.

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

Ten en cuenta que, en cualquiera de los casos, se utilizará el fotograma actual de un video en reproducción. Para procesar varios fotogramas, debes volver a dibujar el video en el lienzo cada vez.

Puedes obtener más información en nuestro artículo sobre cómo aplicar efectos en tiempo real a imágenes y videos.

Guarda los datos de la cámara

La forma más sencilla de guardar los datos de la cámara es usar la API de MediaRecorder.

La API de MediaRecorder tomará la transmisión creada por getUserMedia y, luego, guardará los datos de esta de forma progresiva en tu destino preferido.

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

En nuestro caso, guardamos los datos directamente en un array que luego podemos convertir en un Blob que luego se puede usar para guardar en nuestro servidor web o directamente en el almacenamiento del dispositivo del usuario.

Cómo pedir permiso para usar la cámara de manera responsable

Si el usuario no le otorgó a tu sitio acceso a la cámara antes, en el momento en que llames a getUserMedia, el navegador le pedirá al sitio que le otorgue permiso a la cámara.

A los usuarios no les gusta que se les solicite acceso a los dispositivos potentes en su máquina y con frecuencia bloquean la solicitud, o la ignoran si no comprenden el contexto por el que se creó la solicitud. La práctica recomendada es solicitar acceso a la cámara solo la primera vez que se necesita. Una vez que el usuario haya otorgado acceso, no se le volverá a preguntar, sin embargo, si lo rechaza, no podrás volver a obtener acceso para pedirle permiso.

Usa la API de Permissions para verificar si ya tienes acceso

La API de getUserMedia no te permite saber si ya tienes acceso a la cámara. Esto te presenta un problema: para proporcionar una buena IU para que el usuario te otorgue acceso a la cámara, debes solicitar acceso a ella.

Esto se puede resolver en algunos navegadores usando la API de Permission. La API de navigator.permission te permite consultar el estado de la capacidad de acceder a APIs específicas sin tener que volver a solicitar permiso.

Para consultar si tienes acceso a la cámara del usuario, puedes pasar {name: 'camera'} al método de búsqueda y mostrará lo siguiente:

  • granted: El usuario te otorgó acceso a la cámara anteriormente.
  • prompt: El usuario no te otorgó acceso y se lo solicitará cuando llames a getUserMedia.
  • denied: El sistema o el usuario bloquearon explícitamente el acceso a la cámara y no podrás obtener acceso a ella.

Ahora, puedes comprobar rápidamente si necesitas modificar tu interfaz de usuario para que se adapte a las acciones que el usuario debe realizar.

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

Comentarios