blog tags:

About:

I'm Dmitry Popov,
lead developer and director of Infognition.

Known in the interwebs as Dee Mon since 1997. You could see me as thedeemon on reddit or LiveJournal.

RSS
Articles Technology Blog News Company
Blog
A video codec in JavaScript
November 25, 2017

Recently we released a pure JavaScript implementation of in-browser player for our lossless video codec ScreenPressor. It supersedes our old player made with Flash. Here's some anecdotal evidence of how fast current JavaScript interpreters in browsers are. The chart shows Frames Per Second:

Here we took a screen recording with resolution 1364x768 - 1M pixels, 4MB RGB32 data per frame - and measured how fast our players could decode 480 consequent delta-frames when seeking from 0 (a key frame) to frame 490 (while the next key frame is the 500th). When the player is at position 0 it decodes and buffers a few frames in advance, in this case 10, so when seeking then to frame 490 the number of frames to decode is 480. You can see the test video here (btw this sample shows ~300x lossless compression). "v2" and "v3" mean codec versions: we tested implementations of both 2nd and 3rd versions of ScreenPressor, they use different entropy coders and have other differences.

Of course the speed depends a lot on the video content, how complex and diverse it is, so on different videos numbers will be different. In typical screen videos there are not so many changes from frame to frame, most of the frame can be copied from previous one, this includes scrolling and window movement scenes. But anyway it's quite impressive how a JS-based player can produce 150-200 4MB frames a second.

In this case we can see how different JS speed is in different modern browsers. Firefox Quantum is incredibly fast and smooth when it comes to browsing sites but its JS engine in this test is slower than of MS Internet Explorer and Edge, while Chrome is king when it comes to JS speed.

All JavaScript engines here worked faster than Flash, this probably shows how they evolved since our previous test three years ago. However native code is still 2-4 times faster than JS, thanks to well optimizing vectorizing compiler, more compact data representation and no dynamic types with their runtime costs.

More information about both (JS and Flash) web players for ScreenPressor and more samples here.

Three years ago we experimented with implementing part of the codec in Dart, ASM.js and JS transpiled from Haxe (see the link above) and showed the results to our clients. At that time they did not express much interest, Flash version was fine. This year with further decline of Flash our users turned back to the idea of pure JS implementation. Dart team has abandoned the idea of using the Dart VM in browser, ASM.js did not show stable speed improvements across browsers and now it is getting superseded by WebAssembly. Meanwhile WebAssembly is too young and fresh, not all our corporate users have modern enough browsers to use it. So JS seems like the natural choice today.

Our Flash-based implementation was written in Haxe language. Here we used OpenFL library that provides Flash API on other platforms that Haxe can target, including JS. This explains why the resulting JS player is ~40 times larger in size than the Flash version: it includes large portion of OpenFL that Closure Compiler failed to cut out. With some more work the size of the player can be significantly reduced.

Interestingly, while in native code version 3 of ScreenPressor is usually significantly faster than version 2, its optimizations do not translate directly to implementations in an interpeted language, so the JS version seems to work with video streams from v2 a bit faster than with streams from v3. But anyway even with streams from v3 it's faster than the Flash version that could only deal with v2 streams.