Video Streaming in 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
- Memory efficiency: you don’t need to load large amounts of data in memory before you are able to process it
- 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
- When a video request is made from frontend, we calculate the file size and send few chunks of the video in else statement.
- When we play the video next request to /video made with time range in the headers so we know starting point of next chunk.
- 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).
- 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
I really liked your blog. Really thank you! Really Great. Russell Vandergraph
If some one wishes expert view regarding blogging and site-building then i advise him/her to go to see this blog, Keep up the good work. Tomas Worker
The details talked about within the article are a number of the best out there. Efrain Why
Everything is very open with a very clear explanation of the issues. Randell Dornon
I for all time emailed this website post page to all my contacts,
for the reason that if like to read it after that my friends will too.