Permalink
Browse files

Add a highly experimental decoder for VP8/WebM, under the name of Rou…

…te9.js.

This decoder is a straightforward translation of libvpx and libnestegg via
emscripten, making extensive use of the scaffolding built for Broadway.
Some serious correctness bugs remain, and speed leaves something to be
desired.  So far, the code has only been tested on Firefox 7.
  • Loading branch information...
1 parent a4f39aa commit 33409ef7bb85ae5113b69325f9bc16fc56ae5199 @bemasc committed Nov 30, 2011
Showing with 2,551 additions and 0 deletions.
  1. +6 −0 .gitmodules
  2. +1 −0 AUTHORS
  3. BIN Demo/big-buck-bunny_trailer.webm
  4. +298 −0 Demo/route9.html
  5. +1,207 −0 Demo/route9.js
  6. BIN Demo/sign_irene_cif-V100.webm
  7. +6 −0 README.markdown
  8. +56 −0 vp8/Makefile
  9. +27 −0 vp8/README
  10. +54 −0 vp8/hooks.js
  11. +1 −0 vp8/libvpx
  12. +247 −0 vp8/main.c
  13. +149 −0 vp8/make.py
  14. +1 −0 vp8/nestegg
  15. +37 −0 vp8/paint_2.js
  16. +410 −0 vp8/vpxdec_helpers.c
  17. +51 −0 vp8/yuv2rgb.h
View
@@ -0,0 +1,6 @@
+[submodule "vp8/libvpx"]
+ path = vp8/libvpx
+ url = https://Benjamin.M.Schwartz@code.google.com/r/benjaminmschwartz-libvpx-emscripten/
+[submodule "vp8/nestegg"]
+ path = vp8/nestegg
+ url = git@github.com:bemasc/nestegg.git
View
@@ -5,3 +5,4 @@ Michael Bebenita <mbebenita@gmail.com>
Alon Zakai <alonzakai@gmail.com>
Andreas Gal <gal@mozilla.com>
Mathieu 'p01' Henri <mathieu@p01.org>
+Benjamin M. Schwartz <bens@alum.mit.edu>
Binary file not shown.
View
@@ -0,0 +1,298 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<style>
+/* MetaWebPro font family licensed from fontshop.com. WOFF-FTW! */
+@font-face {
+ font-family: 'MetaBlack';
+ src: url('http://mozcom-cdn.mozilla.net/img/fonts/MetaWebPro-Black.eot');
+ src: local(''),
+ url('http://mozcom-cdn.mozilla.net/img/fonts/MetaWebPro-Black.woff')
+ format('woff');
+ font-weight: bold;
+}
+</style>
+</head>
+<body>
+ <meta charset="utf-8">
+
+ <style>
+
+ #site-title {
+ display: block;
+ font: normal bold 60px/.738 MetaBlack, "Arial Black", sans-serif;
+ letter-spacing: -0.02em;
+ }
+
+ #doc {
+ margin: 0 auto;
+ width: 1200px;
+ padding: 10px;
+ }
+
+ #setting {
+ margin-top: 10px;
+ }
+
+ #tagline {
+ clear: both;
+ font: 1.538em/1.4 Georgia, sans-serif;
+ color: #484848;
+ padding: 0 430px 0 0px;
+ }
+
+ body {
+ font: normal 16px/.738 MetaBlack, "Arial Black", sans-serif;
+ color: #6D7581;
+ }
+
+ select {
+ font: normal 16px "Arial", sans-serif;
+ padding: 1px;
+ color: #6D7581;
+ }
+
+ th {
+ text-align: left;
+ padding: 4px 4px 4px 12px;
+ background: no-repeat;
+ }
+
+ td {
+ padding-left: 8px;
+ text-align: right;
+ }
+
+ #controls {
+ background-color: black;
+ padding: 10px;
+ height: 40px;
+ }
+
+ #play {
+ width: 100px;
+ float: left;
+ }
+
+ #scrubber {
+ margin-left: 120px;
+ margin-top: 12px;
+ margin-right: 10px;
+ }
+
+ </style>
+
+ <link type="text/css" href="jquery/theme/jquery-ui.css" rel="stylesheet" />
+ <script type="text/javascript" src="jquery/jquery.min.js"></script>
+ <script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
+
+ <script type='text/javascript'>
+ var Module = {
+ noInitialRun : true
+ };
+ </script>
+
+ <script src='route9.js' type='text/javascript'></script>
+ <script src="sylvester.js" type="text/javascript"></script>
+ <script src="glUtils.js" type="text/javascript"></script>
+
+ <script src='util.js' type='text/javascript'></script>
+ <script src='canvas.js' type='text/javascript'></script>
+
+ <script type="text/javascript">
+ $(function() {
+ $("#tabs").tabs();
+ $("#play").button();
+ $("#play").click(function() {
+ play();
+ });
+
+ $( "#scrubber" ).slider({
+ range: false,
+ min: 0,
+ max: 500,
+ value: 0,
+ slide: function( event, ui ) {
+ var pos = ui.value / 500;
+ _setPosition(pos);
+ }
+ });
+
+ });
+
+ var scoreCalculated = false;
+ var steadySampleCounter = 0;
+ var steadyFpsCounter = 0;
+
+ function updateStats(fps, fpsSinceStart, elapsed) {
+ var steadyElapsedThreshold = 5;
+ if (elapsed > steadyElapsedThreshold) {
+ steadySampleCounter++;
+ steadyFpsCounter += fps;
+ }
+
+ document.getElementById('fps').innerHTML = fps.toFixed(2);
+ document.getElementById('fpsSinceStart').innerHTML = fpsSinceStart.toFixed(2);
+ document.getElementById('fpsSinceSteady').innerHTML = (steadyFpsCounter / steadySampleCounter).toFixed(2);
+ document.getElementById('elapsed').innerHTML = elapsed.toFixed(2);
+
+ var scoreTimeout = 60;
+ if (elapsed > scoreTimeout && scoreCalculated == false) {
+ scoreCalculated = true;
+ document.getElementById('score').innerHTML = fpsSinceStart.toFixed(2);
+ }
+ if (scoreCalculated == false) {
+ document.getElementById('score').innerHTML = "Calculating: " + (scoreTimeout - elapsed).toFixed(0);
+ }
+ }
+
+ function load() {
+ document.getElementById('downloadProgress').innerHTML = "Downloading, Please Wait ...";
+ var clip = $("#clip").val();
+ var mode = $("#mode").val();
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", clip, false);
+ xhr.responseType = "arraybuffer";
+ xhr.send(null);
+ var arrayBuffer = xhr.response;
+ if (arrayBuffer) {
+ var byteArray = new Uint8Array(arrayBuffer);
+ var array = Array.prototype.slice.apply(byteArray);
+ Module.FS.createDataFile('/', 'video.webm', array, true, false);
+ } else {
+ alert('load fail :(');
+ }
+ document.getElementById('downloadProgress').innerHTML = "Download Complete, Playing ...";
+
+ // Pass canvas and context to the generated code, and do the actual run() here
+ Module.canvas = document.getElementById('canvas');
+
+ if (mode == "none") {
+ _paint = function() {
+ };
+ _SDL_LockSurface = function() {
+ }
+ } else if (mode == "webgl") {
+ _paint = paint;
+ _SDL_LockSurface = function() {};
+ _SDL_Quit = function() {};
+ } else {
+ Module.ctx2D = Module.canvas.getContext('2d');
+ if (!Module.ctx2D) {
+ alert('Canvas not available :(');
+ return;
+ }
+ }
+
+ console.info("Running: " + clip);
+ Module.run(['video.webm']);
+ }
+
+ var loaded = false;
+ var playing = false;
+
+
+ function play() {
+ if (!loaded) {
+ load();
+ loaded = true;
+ }
+
+ if (playing == false) {
+ $('#play').children().first().html("Pause");
+ playing = true;
+ Module.play();
+ } else {
+ $('#play').children().first().html("Play");
+ playing = false;
+ Module.stop();
+ return;
+ }
+ }
+
+ var webGLCanvas = null;
+
+ function updateScrubber() {
+ $("#scrubber").slider('value', _getPosition() * 500);
+ }
+
+ function paint($luma, $cb, $cr, height, width) {
+ if (!webGLCanvas) {
+ webGLCanvas = new YUVWebGLCanvas(Module.canvas, new Size(width, height));
+ }
+ var luma = HEAPU8.subarray($luma);
+ var cb = HEAPU8.subarray($cb);
+ var cr = HEAPU8.subarray($cr);
+
+ webGLCanvas.YTexture.fill(luma);
+ webGLCanvas.UTexture.fill(cb);
+ webGLCanvas.VTexture.fill(cr);
+ webGLCanvas.drawScene();
+ }
+ </script>
+
+
+
+ <div id="doc">
+ <header>
+ <h1 id="site-title"><b>Route9.js</b></h1>
+ <p id="tagline">A VP8/WebM decoder in JavaScript</p>
+ </header>
+ <div>
+ <div id="setting">
+ <span>Clip:
+ <select id="clip" style="margin-left: 10px;">
+ <option value="big-buck-bunny_trailer.webm">Big Buck Bunny Trailer</option>
+ <option value="sign_irene_cif-V100.webm">"Sign Irene" test clip</option>
+ </select>
+ </span>
+ </div>
+ <div id="setting">
+ <span>Render Mode:
+ <select id="mode" style="margin-left: 10px;">
+ <option value="canvas">Canvas</option>
+ <option value="webgl">Canvas w/ WebGL</option>
+ <option value="none">None</option>
+ </select>
+ </span>
+ <span style="margin-left: 10px; border: 0px" id="downloadProgress"></span>
+ </div>
+ <div id="setting">
+ <div style="margin-left: 10px; border: 0px; clear: both;" id="downloadProgress"></div>
+ </div>
+ <div>
+ <div id="player" style="background-color: black; float: left;">
+ <canvas id='canvas' width="640" height="100" style="background-color: #333333;"></canvas>
+ <div id="controls">
+ <button id="play">Play</button>
+ <div id="scrubber"></div>
+ </div>
+ </div>
+ </div>
+ <!-- Stats -->
+ <div
+ style="height: 480px; margin-top: 30px; margin-bottom: 10px; clear: both;">
+ <table style="margin-top: 10px; width: 300;">
+ <tr>
+ <th>FPS</th>
+ <td><span id='fps' style="color: red;"></span></td>
+ </tr>
+ <tr>
+ <th>Average FPS (All / Steady)</th>
+ <td><span id='fpsSinceStart' style="color: green;"></span> /
+ <span id='fpsSinceSteady' style="color: green;"></span></td>
+ </tr>
+ <tr>
+ <th>Elapsed</th>
+ <td><span id='elapsed'></span></td>
+ </tr>
+ <tr>
+ <th>Score</th>
+ <td><span id='score' style="color: brown;"></span></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </body>
+</html>
Oops, something went wrong.

0 comments on commit 33409ef

Please sign in to comment.