J'essaie de configurer un serveur Web qui prendra en charge la diffusion de vidéo en continu sur une balise vidéo HTML5 à l'aide de node.js. Voici mon code jusqu'à présent:
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ù "demande" représente la demande http, le type est soit "application/ogg" ou "vidéo/ogg" (j'ai essayé les deux) et "fichier" est le fichier .ogv 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 quelques problèmes:
Quelqu'un a-t-il des idées sur ce que je peux faire pour que le streaming vidéo fonctionne via node.js?
Merci!
Chris
J'ai pu faire fonctionner cela avec l'aide des forums nodejs:
http://groups.google.com/group/nodejs/browse_thread/thread/8339e0dc825c057f/822b2dd48f36e89
Faits saillants du fil Google Groupes:
Google chrome est connu pour faire d'abord une demande avec la plage 0-1024, puis demander la plage "1024-".
response.end (file.slice (start, chunksize), "binary");
Ensuite:
J'ai réussi à faire jouer la vidéo sans problème dans Firefox en définissant l'en-tête "Connexion" sur "Fermer"
Ensuite:
Semble que vous calculez incorrectement la longueur du contenu:
var chunksize = (end-start) +1;
Si start est 0 et end est 1, dans votre cas, chunksize est 2 et devrait être 1.
Je sais que c'est une très vieille question, mais comme Google semble l'aimer, j'ai pensé qu'il valait la peine de souligner que j'avais écrit un Node.js module de streaming vidéo (Github, ou via NPM) qui, espérons-le, vaut le détour aussi.
Cette solution effectue une lecture asynchrone d'un fichier multimédia vidéo ou audio côté serveur ... elle fait tourner un serveur nodejs à l'URL visible à
il gère également correctement les mouvements du curseur de widget UI avant/arrière HTML5 côté client (navigateur/application)
enregistrer l'extrait de code ci-dessous en tant que fichier côté serveur:
media_server.js
... l'exécuter côté serveur en utilisant
node media_server.js
prendre plaisir
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 + "/");
Sur la base de la réponse de Sam9291, j'ai réécrit la fonction en utilisant createReadStream()
et en corrigeant 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 framework MVC sails.js en plus de Node.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);
});
}
};
J'espère que cela t'aides
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 fil et cela a fonctionné une fois que j'ai traité le fait que la demande initiale (pour "bytes = 0-") l'a fait exploser.
http://elegantcode.com/2011/04/06/taking-baby-steps-with-node-js-pumping-data-between-streams/
Ma mise en œuvre réelle:
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});
}
lorsque vous utilisez express, placez-le dans votre media_server.js ou index.js qui servira les médias sur le port 3000
const express = require('express')
const fs = require('fs')
const path = require('path')
const app = express()
app.use(express.static(path.join(__dirname, 'public')))
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'))
})
app.get('/video', function(req, res) {
const path = 'assets/sample.mp4'// your video path
const stat = fs.statSync(path)
const fileSize = stat.size
const range = req.headers.range
if (range) {
const parts = range.replace(/bytes=/, "").split("-")
const start = parseInt(parts[0], 10)
const end = parts[1]
? parseInt(parts[1], 10)
: fileSize-1
const chunksize = (end-start)+1
const file = fs.createReadStream(path, {start, end})
const head = {
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4',
}
res.writeHead(206, head)
file.pipe(res)
} else {
const head = {
'Content-Length': fileSize,
'Content-Type': 'video/mp4',
}
res.writeHead(200, head)
fs.createReadStream(path).pipe(res)
}
})
app.listen(3000, function () {
console.log('Listening on port 3000!')
})
puis dans votre index.html
<html>
<head>
<title>Video stream sample</title>
</head>
<body>
<video id="videoPlayer" controls muted="muted" autoplay>
<source src="http://localhost:3000/video" type="video/mp4">
</video>
</body>
</html>