Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

A node.js module for streaming and recording HTML5 Theora videos

branch: master
readme.md

This is a node.js module, writen in C++, that produces Theora/Ogg videos from the given RGB buffers.

It was written by Peteris Krumins (peter@catonmat.net). His blog is at http://www.catonmat.net -- good coders code, great reuse.


This module exports several objects that you can work with:

* FixedVideo - to create videos from fixed size frames
* StackedVideo - to create videos from fragmented frames (stack them together)
* AsyncStackedVideo - same as StackedVideo but asynchronous

// these are not there yet, still hacking them in right now.
// * StreamingVideo - to create streamable videos (works with HTML5 <video>)

FixedVideo

FixedVideo object is for creating videos from fixed size frames. That is, each frame is exactly the same size, for example, each frame is 720x400 pixels.

Here is how to use FixedVideo. First you need to create a new instance of this object. The constructor takes two arguments width and height of the video:

var video = new FixedVideo(width, height);

Next, you need to set the output file this video will be written to. This is done via setOutputFile method, it can be relative or absolute path. If nodejs doesn't have the necessary permissions to write the file, it will throw an exception as soon as you submit the first frame. Here is how you use setOutputFile:

video.setOutputFile('./cool_video.ogv');

The .ogv extension stands for ogg-video.

Then you can also change the quality of the video via setQuality method. The quality must be between 0-63, where 0 is the worst quality and 63 is the best. The default quality is 31.

video.setQuality(63);   // best video quality

You can also change the frame rate with setFrameRate. The default is 25fps, to change it do this:

video.setFrameRate(50);  // frame rate is now 50 fps

The keyframe interval can also be controlled. Use setKeyFrameInterval to set it. It must be a power of two:

video.setKeyFrameInterval(128);  // keyframe every 128 frames

Important: All of the above options should be set before submitting the first frame.

Now, to start writing video, call newFrame method with frames sequentially. Frames must be RGB nodejs Buffer objects.

video.newFrame(rgb_frame);

FixedVideo is lazy by itself and will write headers of the video only after receiving the first frame, so the first frame may take longer to encode than subsequent, because there is a lot of initialization going on.

If at any time you're done writing video, call the end method,

video.end();

This will close all open files and free resources. But you can also leave it to garbage collector. If video goes out of scope, it also closes the video file and frees all resources.

StackedVideo

StackedVideo object is for stacking many small frame updates together and then encoding the frame as a whole. Here is how it works. The first frame sent to StackedVideo must be a full frame (the width and height must match video's width and height). Next, you can either send another full frame for encoding or update parts of the last frame. It's useful in a situation like doing a screen recording, when only one smart part of the screen updates, you redraw just that portion and nothing else.

Must of the usage is just like you'd use FixedVideo object.

First create a StackedVideo object:

var stackedVideo = new StackedVideo(width, height);

Then set the output file:

stackedVideo.setOutputFile('./screencast.ogv');

Then set the quality, framerate, keyframe interval, via setQuality, setFrameRate, setKeyFrameInterval methods.

Now you have to submit a full frame to StackedVideo, do it via regular newFrame method:

stackedVideo.newFrame(rgb_frame);

This will encode this frame, and remember it. Now you can use push method to push an update to the frame. The usage is as following:

stackedVideo.push(rgb_rectangle, x, y, width, height);

This will put the rectangle of width x height at position (x, y). Make sure dimensions don't overflow or you'll get an exception. You can also push the first full frame with this method instead of using newFrame, make sure that (x,y) = (0,0) and width, height are video's width, height.

After you're done pushing all the updates you wanted, call endPush. This will encode the frame (and keep the previous frame in memory, so you can push more stuff):

stackedVideo.endPush();

Stacked videos can also duplicate previous frames cheaply to imitate VFR (variable frame rate). Pass millisecond argument to endPush to make it duplicate the previous for the right amount of time. Here is what I mean,

If you call,

stackedVideo.endPush((new Date).getTime());

every time, then the previous frame will be duplicated the right number of times so that video played at the right framerate.

When you're totally done with encoding, call the end method:

stackedVideo.end();

That will close all the file handles and free memory. Alternatively you can let the stackedVideo object go out of scope, which will have the same effect.

AsyncStackedVideo

AsyncStackedVideo is the same as StackedVideo except it's asynchronous.

var asyncVideo = new AsyncStackedVideo(width, height);
asyncVideo.setOutputFile('./video.ogv');

To use it you must specify the temporary directory for fragments (it writes them asynchronously to disk):

asyncVideo.setTmpDir('/tmp/foo');

Next you .push fragments to it, and after you're done with one frame, you call .endPush.

Then when you're totally done with all the frames, call .encode and pass it a callback function, which will be called once the encoding is done:

asyncVideo.encode(function (ok, error) {
    if (ok) {
        // video was written to the file you set by .setOutputFile
    }
    else {
        // failure, examine 'error'
    }
});

StreamingVideo

Also coming near you soon. This is the most awesome stuff!

How to compile?

You need node.js installed to compile this module. When installed it comes with node-waf tool, run it in this libs dir:

node-waf configure build

This will produce video.node dll. After that, make sure NODE_PATH contains lib's dir.

Installation

npm install node-video [-g]

Other stuff in this module

The discovery/ directory contains all the snippets I wrote to understand how to get video working. It's a habit of effective hackers to try lots of small things out until you get the whole picture of how things should work. I call it "the hacker's approach," where you hack stuff up quickly without any understanding, and then rewrite it to produce working modules.

I also tried libx264 but since it was only supported by Chrome, I went with libtheora. Maybe I'll add libx264 later as it gets support from more browsers.

This library was written for my and SubStack's StackVM startup.


Happy videoing!

Sincerely, Peteris Krumins http://www.catonmat.net

Contributors

  • Node v0.3 buffers (James Halliday substack)
  • Node v0.6 compatibility (Pascal Deschenes )
Something went wrong with that request. Please try again.