Vidéo en streaming avec HTML 5 via node.js
j'essaie de configurer un serveur web qui supportera le streaming vidéo vers une balise vidéo HTML5 en utilisant le noeud.js. Voici mon code pour l'instant:
var range = request.headers.range;
var total = file.length;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;
var chunksize = (end-start)+1;
response.writeHead(206, { "Content-Range": "bytes " + start + "-" + end + "/" + total, "Accept-Ranges": "bytes", "Content-Length": chunksize, "Content-Type": type });
response.end(file);
où " request "représente la requête http, tapez" application/ogg "ou" video/ogg "(j'ai essayé les deux) et" file " est le .ogv fichier qui a été lu à partir du système de fichiers. Voici les en-têtes de réponse:
Content-Range bytes 0-14270463/14270464
Accept-Ranges bytes
Content-Length 14270464
Connection keep-alive
Content-Type video/ogg
j'ai examiné les en-têtes de réponse et ce code semble fonctionner correctement, mais il y a un quelques problèmes:
- la vidéo semble se charger très lentement pour être sur un réseau local. De ce que je peux dire en examinant la réponse en utilisant firebug, le fichier semble être streamé à environ 150 kb / sec.
- la vidéo ne fonctionne pas du tout. Même si j'attends que tout se charge, la balise HTML 5 montre juste un grand "x" au lieu d'un film dans firefox.
Merci!
Chris
6 réponses
je sais que c'est une très vieille question, mais que Google semble l'aimer j'ai pensé qu'il serait intéressant de remarquer que j'ai écrit un Nœud.js module de streaming vidéo (Github, ou via NPM) qui, espérons-le, jetez à un œil trop.
j'ai été en mesure d'obtenir que cela fonctionne avec l'aide de l'nodejs forums:
http://groups.google.com/group/nodejs/browse_thread/thread/8339e0dc825c057f/822b2dd48f36e890
les points Saillants de la Google Groupes thread:
Google chrome est connu pour faire d'abord une demande avec la gamme 0-1024 puis demandez la portée " 1024 -".
réponse.fin de fichier (.tranche(démarrer, chunksize), "binaire");
Puis:
j'ai pu obtenir la vidéo pour jouer aucun problème dans firefox en mettant la "connexion" en-tête "fermer"
Puis:
semble que vous calculez incorrectement le contenu-length:
var chunksize = (fin-début)+1;
si start est 0 et end est 1, dans votre cas chunksize est 2, et il devrait 1.
cette solution fait une lecture asynchrone d'un fichier vidéo ou audio côté serveur ... il lance un serveur nodejs à L'URL visible à
en outre, il gère correctement côté client HTML5 (navigateur/application) avant / arrière UI widget mouvements de curseur
enregistrer ci-dessous extrait de code sur le serveur de fichier :
media_server.js
... exécuter côté serveur à l'aide de
node media_server.js
profitez de
var http = require('http'),
fs = require('fs'),
util = require('util');
var path = "/path/to/local/video/or/audio/file/on/server.mp4";
var port = 8888;
var host = "localhost";
http.createServer(function (req, res) {
var stat = fs.statSync(path);
var total = stat.size;
if (req.headers.range) { // meaning client (browser) has moved the forward/back slider
// which has sent this request back to this server logic ... cool
var range = req.headers.range;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;
var chunksize = (end-start)+1;
console.log('RANGE: ' + start + ' - ' + end + ' = ' + chunksize);
var file = fs.createReadStream(path, {start: start, end: end});
res.writeHead(206, { 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/mp4' });
file.pipe(res);
} else {
console.log('ALL: ' + total);
res.writeHead(200, { 'Content-Length': total, 'Content-Type': 'video/mp4' });
fs.createReadStream(path).pipe(res);
}
}).listen(port, host);
console.log("Server running at http://" + host + ":" + port + "/");
basé sur la réponse de Sam9291, j'ai réécrit la fonction en utilisant createReadStream()
et la correction de certains problèmes:
/**
* Sends a static file to the HTTP client, supporting partial transfers.
*
* @req HTTP request object
* @res HTTP response object
* @fn Path to file that should be sent
* @contentType MIME type for the response (defaults to HTML)
*/
function sendFile(req, res, fn, contentType) {
contentType = contentType || "text/html";
fs.stat(fn, function(err, stats) {
var headers;
if (err) {
res.writeHead(404, {"Content-Type":"text/plain"});
res.end("Could not read file");
return;
}
var range = req.headers.range || "";
var total = stats.size;
if (range) {
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;
var chunksize = (end-start)+1;
headers = {
"Content-Range": "bytes " + start + "-" + end + "/" + total,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": contentType
};
res.writeHead(206, headers);
} else {
headers = {
"Accept-Ranges": "bytes",
"Content-Length": stats.size,
"Content-Type": contentType
};
res.writeHead(200, headers);
}
var readStream = fs.createReadStream(fn, {start:start, end:end});
readStream.pipe(res);
});
}
j'utilise le cadre MVC voiles.js en plus de noeud.js et j'ai réussi à le faire fonctionner correctement avec le code suivant:
/**
* VideoController
*
* @module :: Controller
* @description :: Contains logic for handling requests.
*/
var fs = require('fs');
module.exports = {
/* e.g.
sayHello: function (req, res) {
res.send('hello world!');
}
*/
/**
* /video/stream
*/
stream: function (req,res) {
// This will render the view:
// C:\Users\sam\Documents\Dev\Fun\mymoviebank/views/video/stream.ejs
res.view();
},
play: function (req,res) {
fs.readFile('/Users/sam/Videos/big_buck_bunny.mp4', function (err, data) {
if (err) throw err;
var range = req.headers.range;
var total = data.length;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;
var chunksize = (end-start)+1;
res.writeHead(206, { "Content-Range": "bytes " + start + "-" + end + "/" + total, "Accept-Ranges": "bytes", "Content-Length": chunksize, "Content-Type": 'video/mp4' });
res.end(data);
});
}
};
Espérons que cette aide
j'ai trouvé cette solution qui semble être plus simple et (contrairement à la réponse cochée) fonctionne pour moi. (J'ai essayé d'adapter la solution coffeescript à la fin de ce thread et ça a fonctionné une fois que j'ai traité le fait que la requête initiale (pour "bytes=0-") l'explose.
http://elegantcode.com/2011/04/06/taking-baby-steps-with-node-js-pumping-data-between-streams/
Ma mise en œuvre effective:
function stream_response( res, file_path, content_type ){
var readStream = fs.createReadStream(file_path);
readStream.on('data', function(data) {
var flushed = res.write(data);
// Pause the read stream when the write stream gets saturated
console.log( 'streaming data', file_path );
if(!flushed){
readStream.pause();
}
});
res.on('drain', function() {
// Resume the read stream when the write stream gets hungry
readStream.resume();
});
readStream.on('end', function() {
res.end();
});
readStream.on('error', function(err) {
console.error('Exception', err, 'while streaming', file_path);
res.end();
});
res.writeHead(200, {'Content-Type': content_type});
}