Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Node.js HTML5 video streamer
/*
* Inspired by: http://stackoverflow.com/questions/4360060/video-streaming-with-html-5-via-node-js
*/
var http = require('http'),
fs = require('fs'),
util = require('util');
http.createServer(function (req, res) {
var path = 'video.mp4';
var stat = fs.statSync(path);
var total = stat.size;
if (req.headers['range']) {
var range = req.headers.range;
var parts = range.replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = parseInt(partialstart, 10);
var end = partialend ? parseInt(partialend, 10) : total-1;
var chunksize = (end-start)+1;
console.log('RANGE: ' + start + ' - ' + end + ' = ' + chunksize);
var file = fs.createReadStream(path, {start: start, end: end});
res.writeHead(206, { 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/mp4' });
file.pipe(res);
} else {
console.log('ALL: ' + total);
res.writeHead(200, { 'Content-Length': total, 'Content-Type': 'video/mp4' });
fs.createReadStream(path).pipe(res);
}
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
@Premier

This comment has been minimized.

Copy link

commented Feb 23, 2013

It doesn't works

ALL: 17288084
RANGE: 0 - 17288083 = 17288084

stream.js:81
throw er; // Unhandled stream error in pipe.
^
Error: socket hang up
at createHangUpError (http.js:1360:15)
at ServerResponse.OutgoingMessage._writeRaw (http.js:507:26)
at ServerResponse.OutgoingMessage._send (http.js:476:15)
at ServerResponse.OutgoingMessage.write (http.js:749:16)
at ondata (stream.js:38:26)
at EventEmitter.emit (events.js:96:17)
at ReadStream._emitData (fs.js:1368:10)
at afterRead (fs.js:1350:10)
at Object.wrapper as oncomplete

@GiantToast

This comment has been minimized.

Copy link

commented Apr 19, 2013

This saved my life, thanks

@skywalker788

This comment has been minimized.

Copy link

commented Apr 30, 2013

hi paolo rossi,
i read your code.
i didn't think that it was possible to create a streaming server in node (i think it's great!!!)
your code would be useful for onDemand streaming
have you some idea about live Streaming?
in my thesis work i write a gstreamer-app that redirect a stream to icecast server throught shout2send component.
it works but i think that your soluction would be better if it allow as entry an UDP port for example instead of a file
if u've some idea please let discuss about it.
cheers
gennaro

@paolorossi

This comment has been minimized.

Copy link
Owner Author

commented May 8, 2013

@skywalker788 live streaming is a complex problem. This approach cannot work because you must know the file size. A suboptimal solution is HTTP Live Streaming that is widely adopted.

@paolorossi

This comment has been minimized.

Copy link
Owner Author

commented May 8, 2013

@Premier ...line 81?

@SwAinsun

This comment has been minimized.

Copy link

commented Jun 22, 2013

hi @paolorossi, i'm doing simliar work these days and using the chunk stream method, but i've got in trouble with the file hash.
If I download the file with chunk size less then 11.4% of the file size, the new combined file hash will be different from the orignal one. Have you ever came up to this issue or its just a bug or sth. I d like to talk further if you are available.
BTW: im using node.js 0.10.6

@danitetus

This comment has been minimized.

Copy link

commented Sep 11, 2013

Thank you for your code. It has been perfect for me. ;)

@bparvizi

This comment has been minimized.

Copy link

commented Sep 18, 2013

Fantastic work! Works like a charm, thanks.

@psi-4ward

This comment has been minimized.

Copy link

commented Oct 22, 2013

@mitnik

This comment has been minimized.

Copy link

commented Nov 14, 2013

Hi @paolorossi

First, thanks for sharing your code.

I used your code as a start for my project for on-demand streaming. On localhost:4000, the video does not play. I tested the video file in mp4 and webm format both in a separate html file, and they run fine. I ran in chrome and Firefox both but same result. Firefox, though, says corrupt video file. Any ideas about the problem?
Thanks!
Jeet

@RikyTres

This comment has been minimized.

Copy link

commented Dec 17, 2013

Hi @paolorossi,

I'm creating a NodeJS server that stream webm video to clients.
I found this gist really interesting, but I see that it need that the video is on file system, but my app has a buffer with binary video inside.

Is there a way to use a buffer instead path in your code?

The problem could be here:

fs.createReadStream(path, .....
@nestornav

This comment has been minimized.

Copy link

commented Jan 7, 2014

Hi @paolorossi,

Thanks for share you work! This is really helpful to start my work!

@lleo

This comment has been minimized.

Copy link

commented Jan 25, 2014

For this to work you have to point an HTML page with a tag that points at this streamer. Here is a gist of my minor enhancement: https://gist.github.com/lleo/8614403

Oh Use Chrome. Mozilla does't like .mp4 and thats all I tested with. Thought I just tested with Safari and it worked there with .mp4.

@maximilianschmid

This comment has been minimized.

Copy link

commented Mar 1, 2014

awesome. works like a charm.

@tobiastraxel

This comment has been minimized.

Copy link

commented Apr 21, 2014

Hi Paolo, thanks a lot for your code. It helped me understand more about streaming and dealing with the range header.
Running the server on OS X, it works fine with Safari, but fails when using chrome after a while. Chrome sends a ton of requests to the server when playing the video and manually scrubbing forwards and backwards.
The error I got is:

    events.js:72
    throw er; // Unhandled 'error' event
          ^
    Error: EMFILE, open '/Users/..../myvideo.mp4'

What I found out is, that chrome doesn't finish a connection properly before sending another request. Somehow the close event doesn't close the ReadStream.

Placing the following lines after file.pipe(res); shows the difference when using chrome of safari

    res.on('close', function(){
       console.log('response closed');
     });

    res.on('finish', function(){
       console.log('response finished');
    });

closing the file manually in the close event helps:

       res.openedFile = file; 
       file.pipe(res);

       res.on('close', function(){
          console.log('response closed');
          res.openedFile.unpipe(this);
          fs.close(this.openedFile.fd);
     });

However, in the end I decided to use expressjs, which handles the range header out of the box.

@libjared

This comment has been minimized.

Copy link

commented Jun 14, 2014

Wonderful work.

@tsukhu

This comment has been minimized.

Copy link

commented Jun 16, 2014

Excellent example. This worked for me perfectly.. I've just tweeked it a bit for my use by passing the filename as a parameter and added support for the different formats like ogg and webm. See here : https://github.com/tsukhu/rwd-spa-alljs-app/blob/master/routes/video_streamer.js

@sirdiamond

This comment has been minimized.

Copy link

commented Jun 24, 2014

thanks bro, I was looking for something like this to learn more about video stream. Thanks!

@mohammadsaleh

This comment has been minimized.

Copy link

commented Aug 24, 2014

Thank you so much, this worked perfect :-*

@wthit56

This comment has been minimized.

Copy link

commented Aug 28, 2014

Great stuff. Added support for this to my Quick-Host project.

@ccorcos

This comment has been minimized.

Copy link

commented Oct 30, 2014

Now its time for EME!

@nicolsondsouza

This comment has been minimized.

Copy link

commented Nov 14, 2014

Hi,

It works for me that is true,
but I get this error and crash the server if I fast forward it.
Can't render headers after they are sent to the client.
any idea what could be the problem

@foysalit

This comment has been minimized.

Copy link

commented Apr 18, 2015

man you're my hero! seriously, you rock!

@CreeJee

This comment has been minimized.

Copy link

commented Jul 21, 2015

thanks man!

@uhfg123

This comment has been minimized.

Copy link

commented Aug 14, 2015

Is it possible to stream the youtube video through this module? How can i Play youtube video through this module?

@cafe4it

This comment has been minimized.

Copy link

commented Oct 23, 2015

thanks, it works for meteor js too.

@aida-mirabadi

This comment has been minimized.

Copy link

commented Oct 27, 2015

awesome.. Thanks, works for me

@hankphung

This comment has been minimized.

Copy link

commented Nov 16, 2015

This cool but I'm looking for solution to stop the readStream when client close or disconnected. :(

@realinit

This comment has been minimized.

Copy link

commented Jan 2, 2016

var range = req.headers.range;
console.log("range>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "+range);
var total = fs.statSync("/home/nitin/Minecraft + Node.js + Socket.io = Awesome-dTIv_f-Ll2g.mp4").size;// your video size.. you can use fs.statSync("filename").size to get the size of the video if it is stored in a file system
splitq = range.split(/[-=]/),
start = +splitq[1],
end = splitq[2] ? +splitq[2] : total - 1,
chunkSize = end - start + 1;

    var start = parseInt(start, 10);
    var end = end ? parseInt(end, 10) : total - 1;
    var chunksize = (end - start) + 1;
    console.log('RANGE: ' + start + ' - ' + end + ' = ' + chunksize);

Use this one for correct it...enjoy

@rajswarnam

This comment has been minimized.

Copy link

commented Jan 5, 2016

I am having trouble getting stream to work in chrome .. This works perfectly in Mozilla. Any ideas ? Appreciate all your help.

@felipenoris

This comment has been minimized.

Copy link

commented Jan 31, 2016

Thank you!

@deefens

This comment has been minimized.

Copy link

commented Feb 12, 2016

I have the same issue as rajswarnam, works like a charme on all desktop browsers and mobile firefox & safari, but not mobile chrome for android. Console log shows the same request from chrome mobile than chrome desktop, but the player stays blank.

@silvaros

This comment has been minimized.

Copy link

commented Feb 21, 2016

This helped me learn how to do it. Thanks!

@GrimStal

This comment has been minimized.

Copy link

commented Jun 24, 2016

Man, you're the best. I spent two hours for tries to send video correctly. Thank you

@acesama

This comment has been minimized.

Copy link

commented Jul 11, 2016

works like magic , thx

@BlogBlocks

This comment has been minimized.

Copy link

commented Jul 17, 2016

Works fine. I left it as it was and it played video at http://localhost:1337/

I used it to pipe video to my public port http://127.0.0.1:8000/

When the public port received the video it needed no name - just < source src="http://127.0.0.1:1337" type="video/mp4">

It worked fine to broadcast on internet.

@ricardoalcocer

This comment has been minimized.

Copy link

commented Jul 25, 2016

I started this side project based on code on this Gist : https://github.com/ricardoalcocer/node_mediasite

@vijayrajanna

This comment has been minimized.

Copy link

commented Aug 3, 2016

Video streaming server under a minute.. Excellent work !!!

@puigdoalvic

This comment has been minimized.

Copy link

commented Aug 8, 2016

It works! But I have one question,

Can I save the current time ends my video in my Javascript? I need to save the current time when start the video in my navigator and when finished the video in the navigator or when I close my navigator.

@tkanike

This comment has been minimized.

Copy link

commented Dec 22, 2016

Nice work. i need to prevent download option on videos in all browser to the users.

can please help

@steebchen

This comment has been minimized.

Copy link

commented Jan 4, 2017

You're using a sync method using Node.js. That's probably the worst thing you could do since the whole process hangs while .statSync() gets invoked.

@NguyenTungs

This comment has been minimized.

Copy link

commented Feb 15, 2017

Hi @paolorossi.
Thanks for share your code. I want to ask to you a question!
How to prevent download video when streaming for user? Thanks!

@jersobh

This comment has been minimized.

Copy link

commented Apr 24, 2017

How would be a live stream? I mean, this way every time you open "localhost:port", it plays the file from the beginning over again

@realcygnus

This comment has been minimized.

Copy link

commented Jun 25, 2017

great stuff

@shalonteoh

This comment has been minimized.

Copy link

commented Jul 24, 2017

thank you so so much!!!!!

@swagasoft

This comment has been minimized.

Copy link

commented Nov 22, 2018

yea works. But i need help on how to make play on selected video.

@mirajehossain

This comment has been minimized.

Copy link

commented Jan 7, 2019

Thanks, man <3, its works as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.