Video im Web wächst weiterhin sprunghaft an. Eine der Möglichkeiten, wie es wächst, kann durch WebRTC und die Verwendung der einzelnen APIs demonstriert werden. Wir haben ein einfaches Beispiel für die Verwendung von getUserMedia erstellt, um die Webcam eines Benutzers anzufordern und sie in einem Videoelement anzuzeigen. Gehen wir noch einen Schritt weiter und verwenden dieses Beispiel zum Speichern und Transkodieren von Inhalten direkt aus dem Browser.
Erstellen eines getUserMedia-Beispiels
Bevor wir mit den weiteren Schritten beginnen, sehen wir uns das erste, einfachere Beispiel an. Hier wird lediglich der Videostream eines Benutzers angefordert und in einem Videoelement auf der Seite angezeigt. Für das fortgeschrittene Beispiel werden wir jQuery verwenden, also fangen wir hier damit an.
// 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);
});
Jetzt brauchen wir nur noch die Schaltfläche "Medien abrufen" und das Videoelement, und schon kann es losgehen. Nachdem Sie auf die Schaltfläche geklickt und dem Browser den Zugriff auf Ihre Kamera ermöglicht haben, sollte das Endergebnis in etwa so aussehen.
einfaches Bildschirmfoto
Diese Demo sollte mit Firefox, Chrome oder Opera funktionieren.
Jetzt haben Sie über den Browser Zugriff auf die Webcam. Dieses Beispiel ist lustig, aber ziemlich nutzlos, da wir nur jemanden selbst zeigen können.
Einrichten des Media Recorders
Hinweis: Seit 2014 ist Firefox der einzige Browser, der die MediaRecorder-API implementiert hat. Wenn Sie diese Funktion auch in Chrome nutzen möchten, gibt es Projekte wie RecordRTC und MediaStreamRecorder.
Für dieses Beispiel benötigen wir eine einfache serverseitige Komponente, die jedoch nur zwei Aufgaben erfüllen muss:
Geben Sie eine gültige AWS-Richtlinie zurück, damit wir direkt von ihrem Browser aus hochladen können
Übermitteln Sie einen Codierungsauftrag an Zencoder
Für Beispiele wie dieses verwenden wir gerne das Express-Framework für Node, aber wenn Sie sich mit etwas anderem wie Sinatra wohler fühlen, können Sie dieses Beispiel ignorieren und verwenden, was immer Sie möchten. Da wir uns mehr um den clientseitigen Code kümmern, werden wir uns nicht mit der serverseitigen Implementierung befassen.
var S3_BUCKET = 'IHR-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, data);
});
});
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);
});
Dieses Beispiel sollte größtenteils sofort funktionieren, aber Sie müssen die AWS-Konfigurationen bereits eingerichtet haben, ebenso wie die Umgebungsvariable ZENCODER_API_KEY\. Außerdem müssen Sie CORS auf dem von Ihnen verwendeten Bucket konfiguriert haben. Hier ist ein Beispiel für eine funktionierende CORS-Konfiguration:
<?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>
Aufzeichnung von Benutzermedien
Im obigen einfachen Beispiel haben wir die Medien eines Benutzers mit der getUserMedia-API angefordert. Jetzt brauchen wir eine Möglichkeit, diese Inhalte aufzuzeichnen. Glücklicherweise gibt es eine API namens MediaRecorder. Firefox ist der einzige Browser, der sie derzeit unterstützt (ab Version 25), aber es gibt Projekte wie Whammy, die als Pseudo-Shim für andere Browser dienen können.
Die API ist einfach. Wir müssen nur denselben Stream nehmen, den wir im vorherigen Beispiel für die Wiedergabe verwendet haben, und ihn verwenden, um eine neue Instanz von MediaRecorder zu erstellen. Sobald wir unseren neuen Recorder haben, müssen wir nur noch start() aufrufen, um die Aufnahme zu beginnen, und stop(), um sie zu beenden.
var recorder = new MediaRecorder(this.stream);
recorder.start(); // Jetzt wird aufgezeichnet!
// ...Ein paar Sekunden später...
recorder.stop();
Abrufen der aufgezeichneten Medien
Ok, wir haben eine Webcam-Aufnahme gestartet und gestoppt. Wie können wir sie jetzt sehen?
Sie können auf das Ereignis ondataavailable der Instanz von MediaRecorder warten, die wir für die Aufnahme erstellt haben. Danach wird ein neuer Blob aufgenommen, den Sie genau wie die ursprünglichen Benutzermedien wiedergeben können.
// 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();
}
Wenn Sie diese Beispiele mitverfolgt und nachgebaut haben, versuchen Sie wahrscheinlich gerade, das Video erneut abzuspielen und sind frustriert. Leider wird nichts, was Sie "richtig" machen, hier funktionieren. Die Verwendung von Autoplay für das Videoelement und der Aufruf von play() oder das Setzen von currentTime für das Ereignis "ended" führen nicht zum gewünschten Ergebnis.
Dies scheint einfach ein Firefox-Problem bei der Wiedergabe dieser Blobs zu sein. Die funktionale Abhilfe besteht darin, die Quelle beim Ereignis "Ended" einfach zu ersetzen, wenn das Video in einer Schleife abgespielt werden soll.
player.onended = function() {
video.pause();
video.src = blobUrl;
video.play();
}
Der Blob, den Sie haben, ist ein (größtenteils) funktionierendes WebM-Video. Wenn Sie einen Anker-Tag mit dieser Blob-Url als Quelle erstellen, können Sie mit der rechten Maustaste klicken und die Datei lokal speichern. Aber auch lokal verhält sich diese Datei nicht ganz richtig (OS X scheint zu denken, dass es sich um eine HTML-Datei handelt).
Hier passt Zencoder gut ins Bild. Bevor wir sie verarbeiten können, müssen wir die Datei online stellen, damit Zencoder auf sie zugreifen kann. Wir verwenden einen der API-Endpunkte, die wir zuvor erstellt haben, /upload, um eine signierte Richtlinie abzurufen, und verwenden diese dann, um die Datei direkt an S3 zu POSTen (ich verwende in diesem Beispiel 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);
Jetzt haben Sie ein Video in einem S3-Bucket, so dass wir es nur noch verarbeiten müssen. Wie Sie bemerkt haben, haben wir dem Endpunkt /process eine E-Mail hinzugefügt, damit wir die Auftragsbenachrichtigung (einschließlich der Download-Links für das Video) direkt an uns senden können, wenn der Auftrag abgeschlossen ist.
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");
Wenige Sekunden später sollten Sie eine E-Mail erhalten, in der Ihnen zu Ihren brandneuen, im Browser aufgezeichneten Videos gratuliert wird. Die enthaltenen Links sind temporär. Stellen Sie also sicher, dass Sie sie innerhalb von 24 Stunden herunterladen oder den von uns erstellten API-Endpunkt ändern, um die Ausgaben in einen Bucket hochzuladen, den Sie besitzen.
Wir haben eine Demo erstellt, um diese Funktionalität zu demonstrieren, einschließlich einiger kleinerer Stylings und einer nicht ganz so schicken Schnittstelle. Sie heißt VideoBooth, aber Sie können das Projekt gerne klonen und es ausprobieren. Sie können auch mit der funktionierenden Demo auf Heroku spielen.