El vídeo en la web sigue creciendo a pasos agigantados. Una de las formas en que está creciendo se puede demostrar a través de WebRTC y el uso de las API de forma individual. Hemos creado un ejemplo sencillo de uso de getUserMedia para solicitar la cámara web de un usuario y mostrarla en un elemento de vídeo. Para ir un paso más allá, tomemos ese ejemplo y utilicémoslo para guardar y luego transcodificar contenido directamente desde el navegador.
Creación de un ejemplo getUserMedia
Antes de empezar a profundizar en el tema, echemos un vistazo al ejemplo inicial, más sencillo. Todo lo que haremos aquí es solicitar el flujo de vídeo de un usuario, y mostrarlo en un elemento de vídeo en la página. Vamos a utilizar jQuery para el ejemplo más avanzado, así que vamos a seguir adelante y empezar a usarlo aquí.
// Do the vendor prefix dance
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia || navigator.msGetUserMedia;
// Set up an error handler on the callback
var errCallback = function(e) {
console.log(‘Did you just reject me?!’, e);
};
// Request the user’s media
function requestMedia(e) {
e.preventDefault();
// Use the vendor prefixed getUserMedia we set up above and request just video
navigator.getUserMedia({video: true, audio: false}, showMedia, errCallback);
}
// Actually show the media
function showMedia(stream) {
var video = document.getElementById(‘user-media’);
video.src = window.URL.createObjectURL(stream);
video.onloadedmetadata = function(e) {
console.log(‘Locked and loaded.’);
};
}
// Set up a click handler to kick off the process
$(function() {
$(‘#get-user-media’).click(requestMedia);
});
Ahora sólo necesitamos el botón "Get Media" y el elemento de vídeo, y ya estamos listos. Después de hacer clic en el botón y permitir que el navegador acceda a tu cámara, el resultado final debería ser algo parecido a esto.
simple captura de pantalla
Esta demo debería funcionar en Firefox, Chrome u Opera.
Ahora tienes acceso a la webcam a través del navegador. Este ejemplo es divertido, pero bastante inútil, ya que todo lo que podemos hacer es mostrar a alguien a sí mismos.
Configuración de la grabadora multimedia
Nota: A partir de 2014, Firefox es el único navegador que ha implementado la API MediaRecorder. Si quieres que funcione también en Chrome, existen proyectos como RecordRTC y MediaStreamRecorder.
Para este ejemplo necesitamos un componente simple del lado del servidor, pero sólo tiene que hacer dos cosas:
Devolver una política válida de AWS para que podamos cargar directamente desde su navegador
Enviar un trabajo de codificación a Zencoder
Nos gusta usar el framework Express para Node con ejemplos como este, pero si te sientes más cómodo usando otra cosa, como Sinatra, siéntete libre de ignorar este ejemplo y usar lo que quieras. Como estamos más preocupados por el código del lado del cliente, no vamos a profundizar en la implementación del lado del servidor.
var S3_BUCKET = 'YOUR-S3-BUCKET-NAME';
<p>var express = require(‘express’);
var path = require(‘path’);
var logger = require(‘morgan’);
var bodyParser = require(‘body-parser’);
var crypto = require(‘crypto’);
var moment = require(‘moment’);
var AWS = require(‘aws-sdk’);
var s3 = new AWS.S3({ params: { Bucket: S3_BUCKET }});
var zencoder = require(‘zencoder’)();
var app = express();
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(express.static(path.join(__dirname, 'public')));
app.post(‘/process’, function(req, res) {
// Build up the S3 URL based on the specified S3 Bucket and filename included
// in the POST request body.
var input = ‘https://’+S3_BUCKET+’.s3.amazonaws.com/’+req.body.filename;
createJob(input, req.body.email, function(err, data) {
if (err) { return res.send(500, err); }
res.send(200, datos);
});
});
app.post(‘/upload’, function(req, res) {
var cors = createS3Policy();
res.send(201, { url: ‘https://’+S3_BUCKET+’.s3.amazonaws.com/’, cors: cors });
});
function createS3Policy() {
var policy = {
“expiration”: moment().utc().add(‘days’, 1).toISOString(),
“conditions”: [
{ “bucket”: S3_BUCKET },
{ “acl”:”private” },
[ “starts-with”, “$key”, “” ],
[ “starts-with”, “$Content-Type”, “” ],
[ “content-length-range”, 0, 5368709120 ]
]
};
var base64Policy = new Buffer(JSON.stringify(policy)).toString('base64');
var signature = crypto.createHmac('sha1', AWS.config.credentials.secretAccessKey).update(base64Policy).digest('base64');
return {
key: AWS.config.credentials.accessKeyId,
policy: base64Policy,
signature: signature
};
}
function createJob(input, email, cb) {
var watermark = {
url: ‘https://s3.amazonaws.com/zencoder-demo/blog-posts/videobooth.png’,
x: ‘-0’,
y: ‘-0’,
width: ‘30%’
};
zencoder.Job.create({
input: input,
notifications: [ email ],
outputs: [
{ format: ‘mp4’, watermarks: [watermark] },
{ format: ‘webm’, watermarks: [watermark] }
]
}, cb);
}
var server = app.listen(app.get(‘port’), function() {
console.log(‘Express server listening on port ‘ + server.address().port);
});
Este ejemplo debería funcionar en su mayor parte de forma inmediata, pero necesitarás tener las configuraciones de AWS ya establecidas, así como una variable de entorno ZENCODER_API_KEY\. También necesitarás tener configurado CORS en el bucket que utilices. Aquí tienes un ejemplo de configuración CORS que funcionará:
<?xml version=”1.0″ encoding=”UTF-8″?> <CORSConfiguration xmlns=”http://s3.amazonaws.com/doc/2006-03-01/”> <CORSRule> <AllowedOrigin>\*</AllowedOrigin> <AllowedMethod>POST</AllowedMethod> <AllowedHeader>\*</AllowedHeader> </CORSRule> </CORSConfiguration>
Grabación de medios del usuario
En el sencillo ejemplo anterior, hemos solicitado los medios de un usuario mediante la API getUserMedia, así que ahora necesitamos una forma de grabar ese contenido. Por suerte, existe una API llamada MediaRecorder. Firefox es el único navegador que la soporta actualmente (a partir de la versión 25), pero hay proyectos como Whammy que pueden actuar como un pseudo-shim para otros navegadores.
La API es sencilla. Sólo tenemos que tomar el mismo flujo que utilizamos para la reproducción en el ejemplo anterior, y utilizarlo para crear una nueva instancia de MediaRecorder. Una vez que tengamos nuestra nueva grabadora, todo lo que tenemos que hacer es llamar a start() para comenzar a grabar, y a stop() para parar.
var recorder = new MediaRecorder(this.stream);
recorder.start(); // ¡Ahora estás grabando!
// ...Unos segundos después...
recorder.stop();
Obtención de los medios grabados
Vale, hemos iniciado y detenido la grabación de una webcam. ¿Cómo la vemos ahora?
Puedes escuchar el evento ondataavailable en la instancia de MediaRecorder que creamos para grabar. Cuando termine, incluirá un nuevo Blob que podrás reproducir igual que hiciste con el medio original del usuario.
// We’ll keep using the same recorder
recorder.ondataavailable = function(e) {
var videoBlob = new Blob([e.data], { type: e.data.type });
var player = document.getElementById(‘playback-video-el’);
var blobUrl = URL.createObjectURL(videoBlob);
player.src = blobUrl;
player.play();
}
Si has estado siguiendo y construyendo estos ejemplos, ahora mismo probablemente estés intentando volver a ver el vídeo y te estés frustrando. Lamentablemente, nada de lo que hagas "bien" va a funcionar aquí. Usar la reproducción automática en el elemento de vídeo ni llamar a play() o establecer currentTime en el evento finalizado va a hacer lo que quieres.
Esto parece ser simplemente un problema de Firefox con la reproducción de estas manchas. La solución funcional es simplemente reemplazar la fuente en el evento finalizado si desea que el vídeo se reproduzca en bucle.
player.onended = function() {
video.pause();
video.src = blobUrl;
video.play();
}
Este blob que tienes es un vídeo WebM (en su mayor parte) funcional. Si creas una etiqueta de anclaje con la url de este blob como fuente, puedes hacer clic con el botón derecho y guardar el archivo localmente. Sin embargo, incluso localmente, este archivo no se comporta del todo bien (OS X parece pensar que es un archivo HTML).
Aquí es donde Zencoder encaja a la perfección. Antes de poder procesarlo, tenemos que poner el archivo en línea para que Zencoder pueda acceder a él. Utilizaremos uno de los puntos finales de la API que creamos anteriormente, /upload, para obtener una política firmada y, a continuación, utilizarla para enviar el archivo directamente a S3 (en este ejemplo estoy utilizando jQuery).
function uploadVideo(video) {
$.post(‘/upload’, { key: “myawesomerecording.webm” }).done(function(data) {
// The API endpoint we created returns a URL, plus a cors object with a key, policy, and signature.
formUpload(data.url, data.cors.key, data.cors.policy, data.cors.signature, filename, recording);
});
function formUpload(url, accessKey, policy, signature, filename, video) {
var fd = new FormData();</p>
fd.append('key', filename);
fd.append('AWSAccessKeyId', accessKey);
fd.append('acl', 'private');
fd.append('policy', policy);
fd.append('signature', signature);
fd.append('Content-Type', "video/webm");
fd.append("file", video);
$.ajax({
type: ‘POST’,
url: url,
data: fd,
processData: false,
contentType: false
}).done(function(data) {
cb(null);
}).fail(function(jqxhr, status, err) {
cb(err);
});
}
}
uploadVideo(videoBlob);
Ahora tienes un vídeo en un bucket de S3, así que todo lo que tenemos que hacer es procesarlo. Si te has fijado, antes hemos añadido un correo electrónico al punto final /process para que podamos recibir la notificación del trabajo (incluidos los enlaces de descarga del vídeo) directamente cuando haya terminado.
function process(email, filename) {
$.post(‘/process’, {
filename: filename,
email: email
}).done(function(data) {
console.log(‘All done! you should get an email soon.’);
}).fail(function(jqXHR, error, data) {
console.log(‘Awww…sad…something went wrong’);
});
};
process('[email protected]', "myawesomerecording.webm");
Unos segundos después, deberías recibir un correo electrónico felicitándote por tus flamantes vídeos grabados con navegador. Los enlaces incluidos son temporales, así que asegúrate de descargarlos en 24 horas o cambia el punto final de la API que hemos creado para subir los resultados a un bucket de tu propiedad.
Hemos creado una demo para mostrar esta funcionalidad, incluyendo un poco de estilo y una interfaz no tan elegante. Se llama VideoBooth, pero siéntete libre de clonar el proyecto y ejecutarlo. También puedes jugar con la demo en Heroku.