Video Streaming with NodeJS

We can stream video files by utilizing fs.createReadStream(), the server can read the file in a stream rather than reading it all into memory at once. First, we need to create node.js server(here is a code).

var fs = require("fs"),
    http = require("http"),
    url = require("url"),
    path = require("path");

http.createServer(function (req, res) {
  if (req.url = '/movie.mp4') {
    // here will be code :)
  }
}).listen(3000);

We will take care about the Accept-Ranges header  as is required for the HTML5 video controls to work instead of just blindly send the full file. So we should first check the Accept-Ranges header in the incoming request, then read in and send just that bit.

var range = req.headers.range;
var positions = range.replace(/bytes=/, '').split('-');
var start = parseInt(positions[0], 10);

 Now we hava to check requested file and after write reponse header:

fs.stat(file, function(err, stats) {    
    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'
    });
});

The main part, create stream with fs.createReadStream:

var stream = fs.createReadStream(file, { start: start, end: end })
    .on("open", function() {
        stream.pipe(res);
    }).on("error", function(err) {
        res.end(err);
    });

That is all. Here is complete code:

var fs = require('fs'),
    http = require('http'),
    url = require('url'),
    path = require('path');

http.createServer( (req, res)=>{
  if (req.url === '/movie.mp4') {
    var file = path.resolve(__dirname,'movie.mp4');
    var range = req.headers.range;
    var positions = range.replace(/bytes=/, '').split('-');
    var start = parseInt(positions[0], 10);

    fs.stat(file, (err, stats)=>{
      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', ()=>{
          stream.pipe(res);
        }).on('error', (err)=>{
          res.end(err);
        });

        res.on('close', ()=>{
          // close or destroy stream
          stream = null; 
        });
    });    
  }
}).listen(3000);