Video Streaming in Node.js

Video Streaming in Node.js

Featured, Javascript, Node JS

So today i thought to create Video Streaming in Node.js, so lets start with some theory.

What are Streams?

Streams are very powerful concept which Node.js provides. Streams are used to handle reading and writing from a file, network communication and data transfer.

What makes streams unique, is that instead of a program reading a file into memory all at once like in the traditional way, streams read chunks of data piece by piece, processing its content without keeping it all in memory.

This makes streams really powerful when working with large amounts of data, for example, a file size of 5 GB can be larger than your free memory space, making it impossible to read the whole file into the memory in order to process it. In this case we can use streams to ease our life.

If we see Video streaming platforms like youtube or netflix, they do not want you to download whole video at once, instead they provide you data in chunks as you proceed to view the video

So this makes streams

  1. Memory efficiency: you don’t need to load large amounts of data in memory before you are able to process it
  2. Time efficiency: it takes significantly less time to start processing data as soon as you have it, rather than having to wait with processing until the entire payload has been transmitted

Lets jump to practical example.

Add package.json file to your folder

{
  "name": "video-stream-sample",
  "version": "1.0.0",
  "description": "Streaming video example",
  "main": "server.js",
  "engines": {
    "node": ">=6.2.0"
  },
  "scripts": {
    "start": "nodemon server.js"
  },
  "author": "daspinola",
  "license": "MIT",
  "dependencies": {
    "express": "^4.15.3",
    "nodemon": "^1.11.0"
  }
}

Add the below code in server.js

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.htm'))
})

app.get('/getVideo', function(req, res) {
  const path = 'SampleVideo_1280x720_30mb.mp4'
  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

    if(start >= fileSize) {
      res.status(416).send('Requested range not satisfiable\n'+start+' >= '+fileSize);
      return
    }
    
    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!')
})

Add below code in your index.html file

<html>
  <head>
    <title>Video stream sample</title>
  </head>
  <body>
    <video id="videoPlayer" controls muted="muted"> 
      <source src="/video" type="video/mp4">
    </video>
  </body>
</html>

Run npm install and run your project using npm start.

Lets Understand the flow

  1. When a video request is made from frontend, we calculate the file size and send few chunks of the video in else statement.
  2. When we play the video next request to /video made with time range in the headers so we know starting point of next chunk.
  3. Read the file again to create another stream, passing along the new value for the start and the end (which will most likely be the current part that came in the request header and the file size of the video).
  4. We set our 206 header response to send only part of our newly made stream by applying the formula we talked about earlier.

Summary

This is just a example with a simple implementation to understand how to do video streaming in node.js . This is a good start to create a streaming application.

5 comments

Leave a Reply