Stream video with node.js

16,502 views
Skip to first unread message

chrisharrington99

unread,
Dec 5, 2010, 12:11:49 PM12/5/10
to nodejs
Hi there,

I'm trying to set up a web server that will support streaming video to
an HTML5 video tag using node.js. Here's my code so far:

var range = request.headers.range;
var total = file.length;

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;

response.writeHead(206, { "Content-Range": "bytes " + start + "-"
+ end + "/" + total, "Accept-Ranges": "bytes", "Content-Length":
chunksize });
response.end(file);

Where "request" represents the http request and "file" is the .ogv
file that's been read from the file system. Here are the response
headers:

Content-Range bytes 0-14270463/14270464
Accept-Ranges bytes
Content-Length 14270464
Connection keep-alive

I've examined the response headers and this code appears to be working
fine, but there are a couple of problems:

1. The video appears to load very slowly for being on a local
network. From what I can tell examining the response using firebug,
the file appears to be streamed in at about 150 kb/sec.
2. The video doesn't play at all. Even if I wait for the whole
thing to load, the HTML 5 video tag just shows a big "x" instead of a
movie in firefox.

Does anyone have any ideas as to what I can do to get video streaming
working via node.js?

Thanks!
Chris

Nathan Rajlich

unread,
Dec 5, 2010, 12:50:19 PM12/5/10
to nod...@googlegroups.com
Are you sending a "Content-Type" header? That will be required for HTML5 <video>.


--
You received this message because you are subscribed to the Google Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com.
To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nodejs?hl=en.


chrisharrington99

unread,
Dec 5, 2010, 1:52:22 PM12/5/10
to nodejs
Ah. I'd forgotten the Content-Type header. However, after adding it
in, there's no change. New code:

response.writeHead(206, { "Content-Range": "bytes " + start + "-"
+ end + "/" + total, "Accept-Ranges": "bytes", "Content-Length":
chunksize, "Content-Type": type });

Where type is either "video/ogg" or "application/ogg". Neither
produces any visible change.
> > nodejs+un...@googlegroups.com<nodejs%2Bunsu...@googlegroups.com>
> > .

Shimon Doodkin

unread,
Dec 6, 2010, 1:32:50 AM12/6/10
to nodejs

Last time I did something like this with .flv streaming.
I had to parse the file, I had to read and stream by frames.
It is fairly simple. Just to follow the format structure and
start to output from certain count of frames.

On Dec 5, 7:11 pm, chrisharrington99 <chrisharringto...@gmail.com>
wrote:

Shimon Doodkin

unread,
Dec 6, 2010, 1:42:29 AM12/6/10
to nodejs
also each time i had to output the header.

https://gist.github.com/729958

quantum

unread,
Dec 6, 2010, 5:24:35 AM12/6/10
to nodejs
Try

response.end(file, "binary");

quantum

unread,
Dec 6, 2010, 5:29:27 AM12/6/10
to nodejs
Also, make sure you slice the file properly according to requested
range.
Google chrome is known to first make a request with the range 0-1024
and then request the range "1024-".

response.end(file.slice(start, chunksize), "binary");


On Dec 5, 6:11 pm, chrisharrington99 <chrisharringto...@gmail.com>
wrote:

chrisharrington99

unread,
Dec 6, 2010, 1:25:34 PM12/6/10
to nodejs
Thanks for your input, quantum. New code, as per quantum's pointers:

var range = request.headers.range;
var total = file.length;

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;

response.writeHead(206, { "Content-Range": "bytes " + start + "-"
+ end + "/" + total, "Accept-Ranges": "bytes", "Content-Length":
chunksize, "Content-Type": type });
response.end(file.slice(start, end), "binary");

Ok, getting closer! This works, kind of. When the page loads, the
video element sits there and shows the loading animation for exactly
two minutes every time, at which point the retrieved poster is shown
and I can start buffering/playing the video. During these two
minutes, firefox sits there with the loading bar of the page not
moving at all, as if I hadn't called the response.end method in the
request handler (I double checked that I am definitely calling the
response.end method, though). Also during the two minutes of waiting,
firebug reports that there are no ongoing requests, which confuses me
a little. It does say, however, that the latest request is of unknown
size - it just shows a question mark.

Any ideas as to what might be causing this delay?

Thanks!
Chris

Justin Cormack

unread,
Dec 6, 2010, 6:13:51 PM12/6/10
to nod...@googlegroups.com
Compare the http traffic against a known working video. It is not well
documented what the browser wants for video and odd behaviour is
common.

Although last time i had a bad case of this it was a proxy issue.

Justin

> --
> You received this message because you are subscribed to the Google Groups "nodejs" group.
> To post to this group, send email to nod...@googlegroups.com.

> To unsubscribe from this group, send email to nodejs+un...@googlegroups.com.

mscdex

unread,
Dec 6, 2010, 6:21:45 PM12/6/10
to nodejs
On Dec 6, 1:25 pm, chrisharrington99 <chrisharringto...@gmail.com>
wrote:
>     response.end(file.slice(start, end), "binary");
>

The "binary" encoding is deprecated. Assuming 'file' here is
instanceof Buffer, just passing in the slice should be enough
since .write()/.end() can handle buffers and buffers contain binary
data anyway.

chrisharrington99

unread,
Dec 7, 2010, 12:35:28 AM12/7/10
to nodejs
Justin, could you expand on what you mean by a "proxy issue"? I don't
believe that's my problem, but I'd like to rule it out regardless.

On Dec 6, 4:13 pm, Justin Cormack <jus...@specialbusservice.com>
wrote:
> Compare the http traffic against a known working video. It is not well
> documented what the browser wants for video and odd behaviour is
> common.
>
> Although last time i had a bad case of this it was a proxy issue.
>
> Justin
>

chrisharrington99

unread,
Dec 7, 2010, 12:46:22 AM12/7/10
to nodejs
Deprecated or not, if I take the "binary" encoding out, the video
doesn't play at all.

chrisharrington99

unread,
Dec 7, 2010, 12:59:32 AM12/7/10
to nodejs
I was able to get the video to play no problems in firefox by setting
the "connection" header to "close". Chrome is still a pain in my ass,
but one step at a time...

On Dec 6, 10:46 pm, chrisharrington99 <chrisharringto...@gmail.com>
wrote:

quantum

unread,
Dec 7, 2010, 12:42:19 PM12/7/10
to nodejs
Seems that you are incorrectly computing the content-length:

var chunksize = (end-start)+1;

If start is 0 and end is 1, in your case chunksize is 2, and it should
be 1.
That's why you're getting the 'loading' icon forever.

Regards,
Florin


On Dec 7, 6:59 am, chrisharrington99 <chrisharringto...@gmail.com>
wrote:
Reply all
Reply to author
Forward
0 new messages