webm-wasm
webm-wasm lets you create webm videos in JavaScript via WebAssembly. The library consumes raw RGBA32 buffers (4 bytes per pixel) and turns them into a webm video with the given framerate and quality. This makes it compatible out-of-the-box with ImageData
from a <canvas>
. With realtime mode you can also use webm-wasm for streaming webm videos.
Works in all major browsers (although Safari can’t play webm 🐼).
The wasm module was created by emscripten’ing libvpx, libwebm and libyuv.
$ npm install --save webm-wasm
Note: This is a proof-of-concept and not a production-grade library.
Usage
webm-wasm runs in a worker by default. It works on the web and in in Node, although you need Node 11+ with the --experimental-worker
flag.
Quickstart
const worker = new Worker("webm-worker.js");
worker.postMessage("./webm-wasm.wasm");
await nextMessage(worker);
worker.postMessage({
width: 512,
height: 512
});
while (hasNextFrame()) {
const buffer = getFrame();
worker.postMessage(buffer, [buffer]);
}
worker.postMessage(null);
const webm = await nextMessage(worker);
worker.terminate();
(You can find an implementation of nextMessage()
in src/worker/webm-worker.js
)
Constructor options
width
(default: 300
): Width of the video
height
(default: 150
): Height of the video
timebaseNum
(default: 1
): Numerator of the fraction for the length of a frame
timebaseDen
(default: 30
): Denominator of the fraction for the length of a frame
bitrate
(default: 200
): Bitrate in kbps
realtime
(default: false
): Prioritize encoding speed over compression ratio and quality. With realtime mode turned off the worker will send a single ArrayBuffer
containing the entire webm video file once input stream has ended. With realtime mode turned on the worker will send an ArrayBuffer
in regular intervals.
From a CDN
Worker code can’t be loaded from another origin directly, even when the source is CORS-enabled. It is, however, still possible to load webm-wasm from a CDN like unpkg.com with a little workaround:
const buffer = await fetch(
"https://unpkg.com/webm-wasm@<version>/dist/webm-worker.js"
).then(r => r.arrayBuffer());
const worker = new Worker(
URL.createObjectURL(new Blob([buffer], { type: "text/javascript" }))
);
worker.postMessage("https://unpkg.com/webm-wasm@<version>/dist/webm-wasm.wasm");
WebAssembly
If you just want to use the WebAssembly module directly, you can grab webm-wasm.wasm
as well as the the Emscripten glue code webm-wasm.js
.
The WebAssembly module exposes a C++ class via embind:
class WebmEncoder {
public:
WebmEncoder(int timebase_num, int timebase_den, unsigned int width, unsigned int height, unsigned int bitrate, bool realtime, val cb);
bool addRGBAFrame(std::string rgba);
bool finalize();
std::string lastError();
}
Experimental: TransformStreams
Transferable Streams are behind the “Experimental Web Platform Features” flag in Chrome Canary. The alternative webm-transformstreamworker.js
makes use of them to expose the webm encoder. Take a look at the demos to see the usage.
Demos
To run the web demos, start the websever using
$ npm run serve
To run the node demos, run them directly (requires Node 11+):
$ node --experimental-worker ./node-simple.js
Building
Because the build process is completely Dockerized, Docker is required for building webm-wasm.
$ npm install
$ npx napa
$ npm run build
Apache 2.0