使用Node.js将视频文件流式传输到html5视频播放器,以便视频控件继续工作? [英] Streaming a video file to an html5 video player with Node.js so that the video controls continue to work?
问题描述
使用Node将小视频文件流式传输到HTML5视频非常简单
我学习了如何将小视频文件流式传输到非常容易使用HTML5视频播放器。通过此设置,控件无需任何工作即可工作,视频流完美无瑕。具有示例视频的完整工作代码的工作副本为此处在Google文档中下载。
客户:
< HTML>
< title>欢迎< / title>
< body>
<视频控件>
< source src =movie.mp4type =video / mp4/>
< source src =movie.webmtype =video / webm/>
< source src =movie.oggtype =video / ogg/>
<! - - 后备 - >
您的浏览器不支持< code>视频< / code>元件。
< / video>
< / body>
< / html>
服务器:
//声明Vars&读取文件
var fs = require('fs'),
http = require('http'),
url = require('url'),
path = require('path');
var movie_webm,movie_mp4,movie_ogg;
// ... [snip] ...(阅读索引页面)
fs.readFile(path.resolve(__ dirname,movie.mp4),function(err,data){
if(err){
throw err;
}
movie_mp4 = data;
});
// ... [剪辑] ...(阅读其他两种格式的视频)
//服务&流视频
http.createServer(函数(req,res){
// ... [snip] ...(提供客户端文件)
var total;
if(reqResource ==/ morie.mp4){
total = movie_mp4.length;
}
// ... ... [snip] ...处理其他两种格式视频
var range = req.headers.range;
var positions = range.replace(/ bytes = /,)。split( - );
var start = parseInt (position [0],10);
var end = positions [1]?parseInt(positions [1],10):total - 1;
var chunksize =(end - start)+ 1;
if(reqResource ==/ emovie.mp4){
res.writeHead(206,{
Content-Range:bytes+ start + - + end + /+ total,
Accept-Ranges:bytes,
Content-Length:chunksize,
Content-Type:video / mp4
)};
res.end(movie_mp4.slice(start,end + 1),binary);
}
// ... [snip] ...处理两个OTH呃格式为视频
})。listen(8888);
但是这种方法仅限于文件< 1GB大小。
流媒体(任意大小)视频文件 fs.createReadStream
通过使用 fs.createReadStream()
,服务器可以读取流中的文件,而不是全部读入内存中一旦。这听起来像是正确的做事方式,语法非常简单:
服务器代码段:
movieStream = fs.createReadStream(pathToFile);
movieStream.on('open',function(){
res.writeHead(206,{
Content-Range:bytes+ start + - + end + /+ total,
Accept-Ranges:bytes,
Content-Length:chunksize,
Content-Type:video / mp4
});
//这只是将读取流传递给响应对象(它向
//发送到客户端)
movieStream.pipe(res);
});
$ b $ movieStream.on('error',function(err){
res.end(err);
});
这个视频流很好!但视频控制不再有效。 接受范围
标头(<$ c $中的位) c> writeHead())是HTML5视频控件的工作所必需的。
我认为,不要盲目发送完整文件,您应该首先检查REQUEST中的 Accept Ranges
标头,然后读入并发送该位。 fs.createReadStream
支持开始
,以及结束
选项。
所以我试了一个例子,它的工作原理。代码不漂亮,但很容易理解。首先我们处理范围标题以获取开始/结束位置。然后,我们使用 fs.stat
来获取文件的大小,而不必将整个文件读入内存。最后,使用 fs.createReadStream
将请求的部分发送给客户端。
var fs = require(fs),
http = require(http),
url = require(url),
path = require(path) ;
http.createServer(函数(req,res){
if(req.url!=/ moovie.mp4){
res.writeHead(200,{ Content-Type:text / html});
res.end('< video src =http:// localhost:8888 / movie.mp4controls>< / video>');
} else {
var file = path.resolve(__ dirname,movie.mp4);
fs.stat(file,function(err,stats){
if(
if( err){
if(err.code ==='ENOENT'){
// 404错误如果找不到文件
return res.sendStatus(404);
}
res.end(错误);
}
var range = req.headers.range;
if(!range){
// 416错误范围
return res.sendStatus(416);
}
var positions = range.replace(/ bytes = /,)。split( - );
var start = parseInt(位置[0],10);
var total = stats.size;
var end = positions [1]?parseInt(positions [1],10):total - 1;
var chunksize =(结束 - 开始) + 1;
res.writeHead(206,{
Content-Range:bytes+ start + - + end +/+ total,
Accept-Ranges:bytes,
Content-Length:chunksize,
Content-Type:video / mp4
});
var stream = fs.createReadStream(file,{start:start,end:end})
.on(open,function(){
stream.pipe (error,function(err){
res.end(err);
});
})。
});
}
})。listen(8888);
Tl;Dr - The Question:
What is the right way to handle streaming a video file to an html5 video player with Node.js so that the video controls continue to work?
I think it has to do with the way that the headers are handled. Anyway, here's the background information. The code is a little lengthy, however, it's pretty straightforward.
Streaming small video files to HTML5 video with Node is easy
I learned how to stream small video files to an HTML5 video player very easily. With this setup, the controls work without any work on my part, and the video streams flawlessly. A working copy of the fully working code with sample video is here, for download on Google Docs.
Client:
<html>
<title>Welcome</title>
<body>
<video controls>
<source src="movie.mp4" type="video/mp4"/>
<source src="movie.webm" type="video/webm"/>
<source src="movie.ogg" type="video/ogg"/>
<!-- fallback -->
Your browser does not support the <code>video</code> element.
</video>
</body>
</html>
Server:
// Declare Vars & Read Files
var fs = require('fs'),
http = require('http'),
url = require('url'),
path = require('path');
var movie_webm, movie_mp4, movie_ogg;
// ... [snip] ... (Read index page)
fs.readFile(path.resolve(__dirname,"movie.mp4"), function (err, data) {
if (err) {
throw err;
}
movie_mp4 = data;
});
// ... [snip] ... (Read two other formats for the video)
// Serve & Stream Video
http.createServer(function (req, res) {
// ... [snip] ... (Serve client files)
var total;
if (reqResource == "/movie.mp4") {
total = movie_mp4.length;
}
// ... [snip] ... handle two other formats for the video
var range = req.headers.range;
var positions = range.replace(/bytes=/, "").split("-");
var start = parseInt(positions[0], 10);
var end = positions[1] ? parseInt(positions[1], 10) : total - 1;
var chunksize = (end - start) + 1;
if (reqResource == "/movie.mp4") {
res.writeHead(206, {
"Content-Range": "bytes " + start + "-" + end + "/" + total,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": "video/mp4"
});
res.end(movie_mp4.slice(start, end + 1), "binary");
}
// ... [snip] ... handle two other formats for the video
}).listen(8888);
But this method is limited to files < 1GB in size.
Streaming (any size) video files with fs.createReadStream
By utilizing fs.createReadStream()
, the server can read the file in a stream rather than reading it all into memory at once. This sounds like the right way to do things, and the syntax is extremely simple:
Server Snippet:
movieStream = fs.createReadStream(pathToFile);
movieStream.on('open', function () {
res.writeHead(206, {
"Content-Range": "bytes " + start + "-" + end + "/" + total,
"Accept-Ranges": "bytes",
"Content-Length": chunksize,
"Content-Type": "video/mp4"
});
// This just pipes the read stream to the response object (which goes
//to the client)
movieStream.pipe(res);
});
movieStream.on('error', function (err) {
res.end(err);
});
This streams the video just fine! But the video controls no longer work.
The Accept Ranges
header (the bit in writeHead()
) is required for the HTML5 video controls to work.
I think instead of just blindly send the full file, you should first check the Accept Ranges
header in the REQUEST, then read in and send just that bit. fs.createReadStream
support start
, and end
option for that.
So I tried an example and it works. The code is not pretty but it is easy to understand. First we process the range header to get the start/end position. Then we use fs.stat
to get the size of the file without reading the whole file into memory. Finally, use fs.createReadStream
to send the requested part to the client.
var fs = require("fs"),
http = require("http"),
url = require("url"),
path = require("path");
http.createServer(function (req, res) {
if (req.url != "/movie.mp4") {
res.writeHead(200, { "Content-Type": "text/html" });
res.end('<video src="http://localhost:8888/movie.mp4" controls></video>');
} else {
var file = path.resolve(__dirname,"movie.mp4");
fs.stat(file, function(err, stats) {
if (err) {
if (err.code === 'ENOENT') {
// 404 Error if file not found
return res.sendStatus(404);
}
res.end(err);
}
var range = req.headers.range;
if (!range) {
// 416 Wrong range
return res.sendStatus(416);
}
var positions = range.replace(/bytes=/, "").split("-");
var start = parseInt(positions[0], 10);
var total = stats.size;
var end = positions[1] ? parseInt(positions[1], 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"
});
var stream = fs.createReadStream(file, { start: start, end: end })
.on("open", function() {
stream.pipe(res);
}).on("error", function(err) {
res.end(err);
});
});
}
}).listen(8888);
这篇关于使用Node.js将视频文件流式传输到html5视频播放器,以便视频控件继续工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!