188 lines
4.7 KiB
JavaScript
188 lines
4.7 KiB
JavaScript
JSMpeg.WASMModule = (function(){ "use strict";
|
|
|
|
var WASM = function() {
|
|
this.stackSize = 5 * 1024 * 1024; // emscripten default
|
|
this.pageSize = 64 * 1024; // wasm page size
|
|
this.onInitCallbacks = [];
|
|
this.ready = false;
|
|
this.loadingFromFileStarted = false;
|
|
this.loadingFromBufferStarted = false;
|
|
};
|
|
|
|
WASM.prototype.write = function(buffer) {
|
|
this.loadFromBuffer(buffer);
|
|
};
|
|
|
|
WASM.prototype.loadFromFile = function(url, callback) {
|
|
if (callback) {
|
|
this.onInitCallbacks.push(callback);
|
|
}
|
|
|
|
// Make sure this WASM Module is only instantiated once. If loadFromFile()
|
|
// was already called, bail out here. On instantiation all pending
|
|
// onInitCallbacks will be called.
|
|
if (this.loadingFromFileStarted) {
|
|
return;
|
|
}
|
|
this.loadingFromFileStarted = true;
|
|
|
|
this.onInitCallback = callback;
|
|
var ajax = new JSMpeg.Source.Ajax(url, {});
|
|
ajax.connect(this);
|
|
ajax.start();
|
|
};
|
|
|
|
WASM.prototype.loadFromBuffer = function(buffer, callback) {
|
|
if (callback) {
|
|
this.onInitCallbacks.push(callback);
|
|
}
|
|
|
|
// Make sure this WASM Module is only instantiated once. If loadFromBuffer()
|
|
// was already called, bail out here. On instantiation all pending
|
|
// onInitCallbacks will be called.
|
|
if (this.loadingFromBufferStarted) {
|
|
return;
|
|
}
|
|
this.loadingFromBufferStarted = true;
|
|
|
|
this.moduleInfo = this.readDylinkSection(buffer);
|
|
if (!this.moduleInfo) {
|
|
for (var i = 0; i < this.onInitCallbacks.length; i++) {
|
|
this.onInitCallbacks[i](null);
|
|
}
|
|
return;
|
|
}
|
|
|
|
this.memory = new WebAssembly.Memory({initial: 256});
|
|
var env = {
|
|
memory: this.memory,
|
|
memoryBase: 0,
|
|
__memory_base: 0,
|
|
table: new WebAssembly.Table({initial: this.moduleInfo.tableSize, element: 'anyfunc'}),
|
|
tableBase: 0,
|
|
__table_base: 0,
|
|
abort: this.c_abort.bind(this),
|
|
___assert_fail: this.c_assertFail.bind(this),
|
|
_sbrk: this.c_sbrk.bind(this)
|
|
};
|
|
|
|
this.brk = this.align(this.moduleInfo.memorySize + this.stackSize);
|
|
WebAssembly.instantiate(buffer, {env: env}).then(function(results){
|
|
this.instance = results.instance;
|
|
if (this.instance.exports.__post_instantiate) {
|
|
this.instance.exports.__post_instantiate();
|
|
}
|
|
this.createHeapViews();
|
|
this.ready = true;
|
|
for (var i = 0; i < this.onInitCallbacks.length; i++) {
|
|
this.onInitCallbacks[i](this);
|
|
}
|
|
}.bind(this))
|
|
};
|
|
|
|
WASM.prototype.createHeapViews = function() {
|
|
this.instance.heapU8 = new Uint8Array(this.memory.buffer);
|
|
this.instance.heapU32 = new Uint32Array(this.memory.buffer);
|
|
this.instance.heapF32 = new Float32Array(this.memory.buffer);
|
|
};
|
|
|
|
WASM.prototype.align = function(addr) {
|
|
var a = Math.pow(2, this.moduleInfo.memoryAlignment);
|
|
return Math.ceil(addr / a) * a;
|
|
};
|
|
|
|
WASM.prototype.c_sbrk = function(size) {
|
|
var previousBrk = this.brk;
|
|
this.brk += size;
|
|
|
|
if (this.brk > this.memory.buffer.byteLength) {
|
|
var bytesNeeded = this.brk - this.memory.buffer.byteLength;
|
|
var pagesNeeded = Math.ceil(bytesNeeded / this.pageSize);
|
|
this.memory.grow(pagesNeeded);
|
|
this.createHeapViews();
|
|
}
|
|
return previousBrk;
|
|
};
|
|
|
|
WASM.prototype.c_abort = function(size) {
|
|
console.warn('JSMPeg: WASM abort', arguments);
|
|
};
|
|
|
|
WASM.prototype.c_assertFail = function(size) {
|
|
console.warn('JSMPeg: WASM ___assert_fail', arguments);
|
|
};
|
|
|
|
|
|
WASM.prototype.readDylinkSection = function(buffer) {
|
|
// Read the WASM header and dylink section of the .wasm binary data
|
|
// to get the needed table size and static data size.
|
|
|
|
// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
|
|
// https://github.com/kripken/emscripten/blob/20602efb955a7c6c20865a495932427e205651d2/src/support.js
|
|
|
|
var bytes = new Uint8Array(buffer);
|
|
var next = 0;
|
|
|
|
var readVarUint = function () {
|
|
var ret = 0;
|
|
var mul = 1;
|
|
while (1) {
|
|
var byte = bytes[next++];
|
|
ret += ((byte & 0x7f) * mul);
|
|
mul *= 0x80;
|
|
if (!(byte & 0x80)) {
|
|
return ret
|
|
}
|
|
}
|
|
}
|
|
|
|
var matchNextBytes = function(expected) {
|
|
for (var i = 0; i < expected.length; i++) {
|
|
var b = typeof(expected[i]) === 'string'
|
|
? expected[i].charCodeAt(0)
|
|
: expected[i];
|
|
if (bytes[next++] !== b) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
|
|
|
|
|
|
// Make sure we have a wasm header
|
|
if (!matchNextBytes([0, 'a', 's', 'm'])) {
|
|
console.warn('JSMpeg: WASM header not found');
|
|
return null;
|
|
}
|
|
|
|
// Make sure we have a dylink section
|
|
var next = 9;
|
|
var sectionSize = readVarUint();
|
|
if (!matchNextBytes([6, 'd', 'y', 'l', 'i', 'n', 'k'])) {
|
|
console.warn('JSMpeg: No dylink section found in WASM');
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
memorySize: readVarUint(),
|
|
memoryAlignment: readVarUint(),
|
|
tableSize: readVarUint(),
|
|
tableAlignment: readVarUint()
|
|
};
|
|
};
|
|
|
|
WASM.IsSupported = function() {
|
|
return (!!window.WebAssembly);
|
|
};
|
|
|
|
WASM.GetModule = function() {
|
|
WASM.CACHED_MODULE = WASM.CACHED_MODULE || new WASM();
|
|
return WASM.CACHED_MODULE;
|
|
};
|
|
|
|
return WASM;
|
|
|
|
})();
|
|
|