Streaming a video file to an html5 video player with Node.js so that the video controls continue to 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);
Can the server respond with content-length less than requested range if proper headers are used
If you can't satisfy the requested range, you want to respond with 416, and include a Content-Range header telling the client what the satisfiable range actually is. See
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416
If you're really going to handle range requests yourself, you probably want to read the RFC. You need to gracefully handle badly formatted requests, unknown units, multiple ranges, etc. The page I linked above has a link to the current RFC.
Related Topics
How to Scroll to Top of Page With JavaScript/Jquery
Sorting Options Elements Alphabetically Using Jquery
Html Table to Excel JavaScript
Pure JavaScript Method to Wrap Content in a Div
How to Select Multiple Files With ≪Input Type="File"≫
Show and Hide Divs At a Specific Time Interval Using Jquery
Why Is It Bad Practice to Use Links With the JavaScript: "Protocol"
Confirmation Before Closing of Tab/Browser
How to Avoid the Need For Ctrl-Click in a Multi-Select Box Using JavaScript
Replace HTML Page With Contents Retrieved Via Ajax
Uncaught Error: Security_Err: Dom Exception 18 When I Try to Set a Cookie
How to Write in File (User Directory) Using JavaScript
How to Show a Hidden Div When a Select Option Is Selected
Creating Svg Elements Dynamically With JavaScript Inside Html
Print ≪Div Id="Printarea"≫≪/Div≫ Only
How to Get the Background Color Code of an Element in Hex
Modifying CSS Class Property Values on the Fly With JavaScript/Jquery