Video – JavaScript – Capturar video desde una web

Video – JavaScript – Capturar video desde una web

Para probar un concepto, quise crear una grabadora de video muy simple y multiplataforma, así que elegí la web porque funciona en cualquier sistema operativo, incluso en móviles.

He creado una web sencilla para experimentar con el manejo de dispositivos de audio y video desde la web. No tiene mucha complejidad ni Frameworks, solo un poco de Html, Css y Javascript.

Reproducir video

Solo se necesita usar el elemento video de html para mostrar la señal de un dispositivo que tenga el sistema, y con eso basta por la parte del front end.

<video id="video" autoplay></video>

Para la parte de Javascript se requiere algo más que una línea de código, lo primero que hay que hacer es obtener la lista de dispositivos de la siguiente forma.

const devices = await navigator.mediaDevices.enumerateDevices(); 

const cameras = devices.filter(dispositivo => dispositivo.kind === 'videoinput');

El primer paso es obtener los dispositivos, que suelen ser de dos tipos: audiooutput y videoinput. En este ejemplo se seleccionan los dispositivos de imagen, porque son los que queremos mostrar en el elemento video de html. Lo que se obtiene con el código anterior es un array de objetos similar a este:

{
    "deviceId": "781f4b551c88a09fc960dafd9639edcdc257b9ecd9d0cfcfe387554be58b08c8", 

    "kind": "videoinput", 

    "label": "Camera 1", 

    "groupId": "dda24e81ab426e6442f4b0db46a43c6df90e16fb1a02a67250ab6b9c9002fd08" 
}

La propiedad deviceId, que identifica al dispositivo del sistema, es la que nos interesa para reproducir el video en el elemento html de video. Después de esto, el siguiente paso es crear un objeto del tipo MediaStreamConstraints.

const constraints = {

video: {

deviceId: 123,

Width: 1920,

height: 1080,

frameRate: { ideal: 30, max: 30 }

}

};

En la propiedad video de este objeto, se incluyen algunos valores como los del ejemplo. El más importante es el deviceId, que es el dispositivo de video que queremos usar. Las otras propiedades son la resolución y el frameRate, que son importantes para la grabación. Sin embargo, hay que verificar qué resoluciones y cuadros por segundo admite nuestro dispositivo. Una vez tenemos el objeto debemos pasarlo de esta manera para empezar a obtener el stream de video.

const stream = await navigator.mediaDevices.getUserMedia(constraints);

Ahora lo unico que debemos hacer es pasar ese stream de datos hacia nuestro elemento video en html de esta forma.

const videoElement = document.getElementById('video');
videoElement.srcObject = stream;

Y eso sería todo lo que hay que hacer para que el video aparezca en la pantalla sobre elemento video.

Grabar

Para grabar el stream de video en vivo, necesitamos crear un objeto de tipo MediaRecorder que reciba como parámetros el stream y algunas opciones básicas como el mimeType y el bitRate.

const mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=h264', videoBitsPerSecond: bitRate });

El tema de los codecs es algo distinto, ya que no todos los navegadores tienen soporte para los mismos codecs ni contenedores. Por ejemplo, probé en el navegador Edge y este no tiene soporte para el contenedor mp4, por eso usé webm y el codec h264, pero muchos solo admiten los codecs vp8 y vp9. Safari sí que admite el contenedor mp4 y codecs como h264.

Una vez construido este objeto lo que se tiene que hacer es ejecutar el evento start para comenzar a grabar

mediaRecorder.start();

El método anterior ejecutara el evento onstart, que podemos personalizar tal vez para ejecutar alguna acción como en mi caso un contador de segundos.

Una vez que necesitemos detener la grabación hay que ejecutar el método stop.

mediaRecorder.stop();

Este también ejecutara un evento llamado onstop, el cual también podemos extender.

El método stop, al ejecutarse, permite acceder a los datos cuando se encuentren disponibles. Estos se pueden obtener en un evento llamado ondataavailable, que entrega un objeto de tipo BlobEvent. Este objeto tiene una propiedad llamada data, de tipo Blob, que contiene el “video”.

Estos datos de video se guardan en la memoria interna y temporal del navegador, no se guardan directamente en el sistema de archivos si no que tenemos que “descargarlos” como cualquier otro archivo de una web.

Para obtener el video debemos crear una url para acceder al archivo de esta manera:

mediaRecorder.ondataavailable = function (event) {
const { data } = event;
if (data && data.size > 0) {
const url = URL.createObjectURL(data);
const downloadLink = document.getElementById('downloadLink');
downloadLink.href = url;
downloadLink.download = 'recorded_video.webm';
downloadLink.style.display = 'block';
}
};

El código anterior se encarga de obtener los datos de video y, si existen, generar la url que dirige al archivo y mostrarla en el navegador con el elemento de url: Descargar Video

Con ello obtendremos un link de descarga para el archivo y así obtenemos el video.

Y eso sería todo, dejo el enlace a Github para descargar el proyecto que hice a modo de demo.

Proyecto en Github

Compatibilidad de MediaRecorder en los navegadores.

Captura del proyecto

Video Screen Shoot

Notas

Es necesario tener en cuenta varios aspectos, el primero y tras hacer algunas pruebas con navegadores como Mozilla, Safari, Chrome y Edge (estos dos últimos se podrían considerar lo mismo), es el asunto de los codecs y contenedores, como dije solo Safari admite mp4, además los otros al usar un contenedor webm no almacenan metadatos del video, algo tan simple como la duración del video no se almacena por lo que al reproducir el archivo en un reproductor no sabrás la duración solo se reproducirá hasta el final, cosa que si hace Safari.

En la parte inicial del proyecto tengo un loop para ir verificando los codecs soportados por el navegador, pero solo a modo de referencia, no los uso realmente.

Agregar la duración de video a los metadatos requeriría modificar el Blob a nivel binario y guardar la duración aparte, lo que va más allá del alcance de este blog. 

Lo que si hice fue crear un temporizador para mostrar el tiempo que va grabando, pero a nivel web, con esta información se podría meter a los metadatos.