webm-wasm lets you create webm videos in JavaScript via WebAssembly.
Clone or download
Latest commit 07daa9b Jan 10, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
demo Fix non-realtime output Jan 9, 2019
dist Use AddGenericFrame() to set frame duration Jan 9, 2019
src Use AddGenericFrame() to set frame duration Jan 9, 2019
.gitignore Add build artifacts Dec 31, 2018
CODEOWNERS Licenses and stuff Dec 30, 2018
CONTRIBUTING Licenses and stuff Dec 30, 2018
CONTRIBUTORS Licenses and stuff Dec 30, 2018
Dockerfile Licenses and stuff Dec 30, 2018
LICENSE Licenses and stuff Dec 30, 2018
README.md Fix non-realtime output Jan 9, 2019
build.sh Remove EXPORT_NAME Jan 9, 2019
package-lock.json 0.4.1 Jan 10, 2019
package.json 0.4.1 Jan 10, 2019

README.md

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

// 1. Load the `webm-wasm.js` file in a worker
const worker = new Worker("webm-worker.js");
// 2. Send the path to the `.wasm` file
worker.postMessage("./webm-wasm.wasm");
// 3. Wait for the worker to be ready
await nextMessage(worker);
// 4. Send the parameters for the constructor
worker.postMessage({
  width: 512,
  height: 512
  // ... more constructor options below
});
// 5. Start sending frames!
while (hasNextFrame()) {
  // ArrayBuffer containing RGBA24 data
  const buffer = getFrame();
  worker.postMessage(buffer, [buffer]);
}
// 6. Signal end-of-stream
worker.postMessage(null);
// 7. Get the webm file as an ArrayBuffer
const webm = await nextMessage(worker);
// 8. Cleanup
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");
// Continue as normal

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:
    // Same options as above. `cb` is a callback function that takes an ArrayBuffer.
    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