Captura de vídeo con HTML5

Las posibilidades que ofrecen las aplicaciones basadas en HTML5 y Javascript cada vez se aproximan más a las de las aplicaciones nativas. Por supuesto, una aplicación nativa siempre podrá conseguir un rendimiento mejor y acceder a APIs más específicas y completas, pero en muchos casos el soporte que encontramos en aplicaciones web es suficiente para lo que necesitamos hacer.

En este post vamos a ver un ejemplo sencillo de cómo capturar vídeo a través de la cámara del equipo (ya sea cámara de fotos, webcam, etc.).

OJO: Ten en cuenta que todas estas APIs están todavía en evolución, por lo que el soporte varía dependiendo del navegador y, posiblemente, si lees este post dentro de unos cuantos meses, haya que hacer algunas adaptaciones en el código.

El origen de todo: getUserMedia

El API básica para acceder a los dispositivos de grabación es navigator.getUserMedia. Irónicamente, según la documentación de Mozilla ya está obsoleta, pero la versión nueva navigator.mediaDevices.getUserMedia sólo está soportada de momento en Firefox, así que por ahora usaremos la versión antigua, que presenta la siguiente forma:

navigator.getUserMedia(constraints, successCallback, errorCallback);

Para variar, es un API asíncrona, por lo que recibirá las dos callbacks de rigor, una invocada cuando se completa la operación con éxito y otra cuando se produce algún error, y además recibe un objeto, constraints que nos permite indicar qué queremos recibir (video, audio o ambos), qué formato queremos, si queremos usar la cámara frontal o trasera, etc.

En su versión más simple, podemos invocar este API así:

navigator.getUserMedia(
  {video: true}, 
  function(stream) {
    // Hacer algo con el stream de video 
  }, 
  function(error) {
    // Procesar el error
  });

Al invocarla, se solicitará al usuario permiso para acceder al dispositivo de grabación de video (por defecto la webcam del PC -si la tiene-, o la cámara frontal del móvil), y en caso afirmativo, se llamará nuestra callback con un stream. Y eso nos lleva al siguiente punto, ¿qué hago con el stream?

De streams a URLs

El stream obtenido a través de getUserMedia es un MediaStream que encapsula una o más pistas de audio o video. Al igual que getUserMedia, forma parte del API de WebRTC y es una especifición no definitiva que, a día de hoy, todavía no está soportada en todos los navegadores.

Aunque MediaStream nos permite hacer bastante cosas con el video, nosotros, de momento, sólo queremos mostrarlo en pantalla, por ejemplo dentro de un elemento <video>, y para ello necesitamos alguna forma de poder referenciarlo a través de una URL para usarlo con src del elemento <video>.

Para obtener una url referenciable a partir del MediaStreamm podemos utilizar la función window.URL.createObjectURL. Esta función puede trabajar sobre varios tipos de objetos, entre ellos File o Blob y nos permite obtener una url «temporal» que representa al objeto. Por ejemplo, usando blobs, podríamos construir una imagen en formato png «byte a byte» en un array, y luego con createObjectURL obtener una URL para usarla en un elemento <img>.

Es importante tener en cuenta que las URLs que creemos que con createObjectURL consumirán recursos (especialmente memoria) que no serán liberados hasta que se descargue la página, por lo que se recomienda liberarlos cuando dejes de utilizarlos invocando la función revokeObjectURL.

Ahora tenemos las piezas necesarias para montar nuestra primera prueba de captura de video:

<!DOCTYPE html>
<html>
  <head>
  </head>

  <body>
    <video autoplay="true"/>
    <script src="index.js"></script>
  </body>
</html>
navigator.getUserMedia = navigator.getUserMedia ||  
                         navigator.webkitGetUserMedia || 
                         navigator.mozGetUserMedia || 
                         navigator.msGetUserMedia;
                         
window.URL = window.URL || 
             window.webkitURL || 
             window.mozURL || 
             window.msURL;

window.addEventListener('load', function() {
  
  navigator.getUserMedia({
      video: true
    }, 
    function(stream) {
      var src = window.URL.createObjectURL(stream),
          video = document.querySelector('video');
      video.src = src;      
    }, 
    function(e) {
      console.log(e);
    });
  
}, false);

Aquí os dejo un ejemplo funcionando para que podáis jugar con él.

Capturando un imagen estática

Una situación bastante frecuente es que queramos capturar una imagen estática del vídeo. En otras palabras, hacer una foto. Esto es bastante sencillo utilizando un elemento <canvas> sobre el que mostrar la imagen.

El código para hacerlo es muy simple:

var button = document.querySelectorAll('button'),
    canvas = document.querySelectorAll('canvas'),
    ctx = canvas.getContext('2d');

button.addEventListener('click', function() {
  ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
}, false);

Os dejo otro ejemplo ejecutable.

En la vida real habría que ajustar el tamaño del canvas en base al tamaño del vídeo para respetar las proporciones de la imagen, cosa que podríamos hacer usando el evento loadeddata del elemento video.

Si quisiéramos enviar la imagen capturada a un servidor, la función toDataURL del objeto canvas nos permite obtener un string en base64 con la imagen que se está mostrando en el canvas en ese momento.

Resumen

Aunque siempre andarán un paso por detrás de las APIs nativas, las APIs que ofrece HTML5 son suficientes para muchos casos y nos permiten crear aplicaciones independientes del dispositivo (que no tanto del navegador, ojo) y fáciles de desplegar (básicamente porque no tienen despliegue).

Con las APIs que hemos visto en este post puedes empezar a jugar con la captura de vídeo y de imágenes estáticas, requisito cada vez más habitual en muchas aplicaciones en la que el usuario necesita añadir información de una forma rápida o visual (por ejemplo, para generar un parte de accidente, registrar un gasto con un ticket de aparcamiento, etc.).

4 comentarios en “Captura de vídeo con HTML5

  1. hola, esta bueno el ejemplo del streaming pero me gustaria saber como haces para compartir con otras personas la url de esa aplicacion donde estas transmitiendo el video por tu camara, tengo un servdor centos6 que tiene una camara usb y deseo ponerle esta aplicacion y que otras personas puedan ver lo que esta transmitiendo el servidor, gracias por tu respuesta

  2. Lo que sucede es que tu codigo no me ejecuta en el localhost, lo modifique y me funciona pero a la hora de subirlo al servidor publico no me funciona ni el que descargo de Edit Fiffle o el mofdificado.
    Me puedes colaborar

  3. tengo el mismo problema del comentario anterior no me funciona en mi servidor pero en el localhost del xammpp si

  4. Muito obrigado pelo artigo! Preciso de uma ajuda, agradeceria se fizesse um artigo que mencionasse escolher a camara, junto do exemplo de envio ao servidor

Comentarios cerrados.