Badass JavaScript

A showcase of awesome JavaScript that pushes the boundaries of what's possible on the web, by @devongovett.

WebM and WebP Hand Ported to JavaScript for All Browsers

February 7th 2012

Dominik Homberger has been very busy over the last few months working on porting first, Google’s WebP image format to JS and today launching his WebM video decoder in JavaScript.  No, these are not Emscripten compiled versions - these are hand ports directly from the original C++ source code.  And yes, both of these ports work in all browsers, not just the latest Chrome and Firefox - all browsers.  The WebP port works in IE6+ with a flash fallback for the canvas element, as well as, of course, Chrome, Firefox, Safari and Opera and the mobile browsers on Android and iOS.  The WebM video port works in IE9+, as well as all the other browsers mentioned before including the mobile ones.  That is seriously impressive!

WebP Decoding and Encoding in JavaScript

Let’s first discuss the WebP image port to JavaScript.

WebP is a new image format that provides lossless and lossy compression for images on the web. WebP lossless images are 28% smaller in size compared to PNGs. WebP lossy images are 25-34% smaller in size compared to JPEG images at equivalent SSIM index.

Unfortunately, at the moment the only browser providing native support for WebP is Google’s own Chrome, so if one wants to use WebP encoded images on the web they either have to encode PNGs or JPEGs as well, or use a library like WebPJS to fill the gaps in browser support.  All one has to do to enable WebP support in all browsers is include WebPJS, and it takes care of replacing all the WebP images on the page with decoded equivalents on the fly.

Dominik told me that he didn’t know about Emscripten, the LLVM to JavaScript compiler at the time he started working on the project, so it is all hand ported, but that at one point he did try it just to see how it compared.  He told me that the Emscripten version was actually much slower than he expected, as well as being 600KB in size.  By comparison, the hand ported version is just 67KB minified, 27KB gzipped.

If you want to use the decoder in a more direct fashion rather than automatically replacing your images, you can check out the library behind it called LibWebPJS, which has a nice JavaScript API to the decoder.  He has also ported the encoder to JavaScript as well, so you can encode a WebP image from a PNG or JPEG, as well as support for the lossless version of WebP.

WebM Decoding in JS

Wow, that’s a lot, but not enough it seems!  He also ported the WebM video format to JS.  WebM is a bit more popular than WebP so far (it is also older), and is already supported natively in Chrome, Firefox, and Opera.  Dominik’s WebM port to JavaScript works in all modern browsers including IE9+ and mobile browsers, however your results in terms of actual framerate may vary across browsers and platforms.  I get about 10fps in Safari and about 25-30 in Chrome and Firefox Aurora, so not too shabby for a first pass.  On my iPhone 4S by comparison, while the video does play, I get about 1 frame per second, so certainly room for improvement there, but who expected it to even work at all?

We’ve seen H.264 and WebM playing in JavaScript before, but never hand ported - always Emscripten ports - and never working in all browsers.  This is seriously impressive stuff! There is still some work to be done in terms of performance on some browsers, but the proof of concept is here.  I can’t wait to see what comes next!