Selaa lähdekoodia

Add WebAssembly mpeg1 video and mp2 audio decoder

phoboslab 7 vuotta sitten
vanhempi
commit
47daa9d63b
15 muutettua tiedostoa jossa 3244 lisäystä ja 16 poistoa
  1. 76 2
      build.sh
  2. 4 3
      jsmpeg.min.js
  3. 2 0
      src/buffer.js
  4. 21 5
      src/decoder.js
  5. 18 1
      src/jsmpeg.js
  6. 106 0
      src/mp2-wasm.js
  7. 115 0
      src/mpeg1-wasm.js
  8. 36 5
      src/player.js
  9. 148 0
      src/wasm-module.js
  10. 189 0
      src/wasm/buffer.c
  11. 31 0
      src/wasm/buffer.h
  12. 703 0
      src/wasm/mp2.c
  13. 22 0
      src/wasm/mp2.h
  14. 1746 0
      src/wasm/mpeg1.c
  15. 27 0
      src/wasm/mpeg1.h

+ 76 - 2
build.sh Näytä tiedosto

@@ -1,5 +1,63 @@
1 1
 #!/bin/sh
2
-uglifyjs \
2
+
3
+
4
+# Build the .wasm Module first
5
+
6
+# Since we're compiling a side module here, so that we can load it without the
7
+# runtime cruft, we have to explicitly compile in support for malloc and
8
+# friends.
9
+# Note memcpy, memmove and memset are explicitly exported, otherwise they will
10
+# be eliminated by the SIDE_MODULE=2 setting - not sure why that happens.
11
+emcc \
12
+	src/wasm/mpeg1.c \
13
+	src/wasm/mp2.c \
14
+	src/wasm/buffer.c \
15
+	$EMSCRIPTEN/system/lib/emmalloc.cpp \
16
+	$EMSCRIPTEN/system/lib/libc/musl/src/string/memcpy.c \
17
+	$EMSCRIPTEN/system/lib/libc/musl/src/string/memmove.c \
18
+	$EMSCRIPTEN/system/lib/libc/musl/src/string/memset.c \
19
+	-s WASM=1 \
20
+	-s SIDE_MODULE=2 \
21
+	-s TOTAL_STACK=5242880\
22
+	-s USE_PTHREADS=0 \
23
+	-s LEGALIZE_JS_FFI=0\
24
+	-s NO_FILESYSTEM=1 \
25
+	-s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE="[]" \
26
+	-s "EXPORTED_FUNCTIONS=[
27
+		'_memcpy',
28
+		'_memmove',
29
+		'_memset',
30
+		'_mpeg1_decoder_create',
31
+		'_mpeg1_decoder_destroy',
32
+		'_mpeg1_decoder_get_write_ptr',
33
+		'_mpeg1_decoder_get_index',
34
+		'_mpeg1_decoder_set_index',
35
+		'_mpeg1_decoder_did_write',
36
+		'_mpeg1_decoder_has_sequence_header',
37
+		'_mpeg1_decoder_get_frame_rate',
38
+		'_mpeg1_decoder_get_coded_size',
39
+		'_mpeg1_decoder_get_width',
40
+		'_mpeg1_decoder_get_height',
41
+		'_mpeg1_decoder_get_y_ptr',
42
+		'_mpeg1_decoder_get_cr_ptr',
43
+		'_mpeg1_decoder_get_cb_ptr',
44
+		'_mpeg1_decoder_decode',
45
+		'_mp2_decoder_create',
46
+		'_mp2_decoder_destroy',
47
+		'_mp2_decoder_get_write_ptr',
48
+		'_mp2_decoder_get_index',
49
+		'_mp2_decoder_set_index',
50
+		'_mp2_decoder_did_write',
51
+		'_mp2_decoder_get_left_channel_ptr',
52
+		'_mp2_decoder_get_right_channel_ptr',
53
+		'_mp2_decoder_get_sample_rate',
54
+		'_mp2_decoder_decode']" \
55
+	-O3 \
56
+	-o jsmpeg.wasm
57
+
58
+
59
+# Concat all .js sources
60
+cat \
3 61
 	src/jsmpeg.js \
4 62
 	src/video-element.js \
5 63
 	src/player.js \
@@ -10,8 +68,24 @@ uglifyjs \
10 68
 	src/ts.js \
11 69
 	src/decoder.js \
12 70
 	src/mpeg1.js \
71
+	src/mpeg1-wasm.js \
13 72
 	src/mp2.js \
73
+	src/mp2-wasm.js \
14 74
 	src/webgl.js \
15 75
 	src/canvas2d.js \
16 76
 	src/webaudio.js \
17
-	-o jsmpeg.min.js
77
+	src/wasm-module.js \
78
+	> jsmpeg.js
79
+
80
+# Append the .wasm module to the .js source as base64 string
81
+echo "JSMpeg.WASM_BINARY_INLINED='$(base64 -w 0 jsmpeg.wasm)';" \
82
+	>> jsmpeg.js
83
+
84
+
85
+# Minify
86
+uglifyjs jsmpeg.js -o jsmpeg.min.js
87
+
88
+# Cleanup
89
+rm jsmpeg.js
90
+rm jsmpeg.wasm
91
+

File diff suppressed because it is too large
+ 4 - 3
jsmpeg.min.js


+ 2 - 0
src/buffer.js Näytä tiedosto

@@ -99,6 +99,8 @@ BitBuffer.prototype.write = function(buffers) {
99 99
 	else {
100 100
 		this.appendSingleBuffer(buffers);
101 101
 	}
102
+
103
+	return totalLength;
102 104
 };
103 105
 
104 106
 BitBuffer.prototype.appendSingleBuffer = function(buffer) {

+ 21 - 5
src/decoder.js Näytä tiedosto

@@ -5,6 +5,7 @@ var BaseDecoder = function(options) {
5 5
 	this.canPlay = false;
6 6
 
7 7
 	this.collectTimestamps = !options.streaming;
8
+	this.bytesWritten = 0;
8 9
 	this.timestamps = [];
9 10
 	this.timestampIndex = 0;
10 11
 
@@ -14,20 +15,34 @@ var BaseDecoder = function(options) {
14 15
 	Object.defineProperty(this, 'currentTime', {get: this.getCurrentTime});
15 16
 };
16 17
 
18
+BaseDecoder.prototype.destroy = function() {};
19
+
17 20
 BaseDecoder.prototype.connect = function(destination) {
18 21
 	this.destination = destination;
19 22
 };
20 23
 
24
+BaseDecoder.prototype.bufferGetIndex = function() {
25
+	return this.bits.index;
26
+};
27
+
28
+BaseDecoder.prototype.bufferSetIndex = function(index) {
29
+	this.bits.index = index;
30
+};
31
+
32
+BaseDecoder.prototype.bufferWrite = function(buffers) {
33
+	return this.bits.write(buffers);
34
+};
35
+
21 36
 BaseDecoder.prototype.write = function(pts, buffers) {
22 37
 	if (this.collectTimestamps) {
23 38
 		if (this.timestamps.length === 0) {
24 39
 			this.startTime = pts;
25 40
 			this.decodedTime = pts;
26 41
 		}
27
-		this.timestamps.push({index: this.bits.byteLength << 3, time: pts});
42
+		this.timestamps.push({index: this.bytesWritten << 3, time: pts});
28 43
 	}
29 44
 
30
-	this.bits.write(buffers);
45
+	this.bytesWritten += this.bufferWrite(buffers);
31 46
 	this.canPlay = true;
32 47
 };
33 48
 
@@ -46,11 +61,11 @@ BaseDecoder.prototype.seek = function(time) {
46 61
 
47 62
 	var ts = this.timestamps[this.timestampIndex];
48 63
 	if (ts) {
49
-		this.bits.index = ts.index;
64
+		this.bufferSetIndex(ts.index);
50 65
 		this.decodedTime = ts.time;
51 66
 	}
52 67
 	else {
53
-		this.bits.index = 0;
68
+		this.bufferSetIndex(0);
54 69
 		this.decodedTime = this.startTime;
55 70
 	}
56 71
 };
@@ -62,8 +77,9 @@ BaseDecoder.prototype.decode = function() {
62 77
 BaseDecoder.prototype.advanceDecodedTime = function(seconds) {
63 78
 	if (this.collectTimestamps) {
64 79
 		var newTimestampIndex = -1;
80
+		var currentIndex = this.bufferGetIndex();
65 81
 		for (var i = this.timestampIndex; i < this.timestamps.length; i++) {
66
-			if (this.timestamps[i].index > this.bits.index) {
82
+			if (this.timestamps[i].index > currentIndex) {
67 83
 				break;
68 84
 			}
69 85
 			newTimestampIndex = i;

+ 18 - 1
src/jsmpeg.js Näytä tiedosto

@@ -92,7 +92,23 @@ var JSMpeg = {
92 92
 				array[i] = value;
93 93
 			}
94 94
 		}
95
-	}
95
+	},
96
+
97
+	Base64ToArrayBuffer: function(base64) {
98
+		var binary =  window.atob(base64);
99
+		var length = binary.length;
100
+		var bytes = new Uint8Array(length);
101
+		for (var i = 0; i < length; i++)        {
102
+			bytes[i] = binary.charCodeAt(i);
103
+		}
104
+		return bytes.buffer;
105
+	},
106
+
107
+	// The build process may append `JSMpeg.WASM_BINARY_INLINED = base64data;` 
108
+	// to the minified source.
109
+	// If this property is present, jsmpeg will use the inlined binary data
110
+	// instead of trying to load a jsmpeg.wasm file via Ajax.
111
+	WASM_BINARY_INLINED: null
96 112
 };
97 113
 
98 114
 // Automatically create players for all found <div class="jsmpeg"/> elements.
@@ -103,3 +119,4 @@ else {
103 119
 	document.addEventListener('DOMContentLoaded', JSMpeg.CreateVideoElements);
104 120
 }
105 121
 
122
+

+ 106 - 0
src/mp2-wasm.js Näytä tiedosto

@@ -0,0 +1,106 @@
1
+JSMpeg.Decoder.MP2AudioWASM = (function(){ "use strict";
2
+
3
+// Based on kjmp2 by Martin J. Fiedler
4
+// http://keyj.emphy.de/kjmp2/
5
+
6
+var MP2WASM = function(options) {
7
+	JSMpeg.Decoder.Base.call(this, options);
8
+
9
+	this.module = options.wasmModule;
10
+
11
+	this.bufferSize = options.audioBufferSize || 128*1024;
12
+	this.bufferMode = options.streaming
13
+		? JSMpeg.BitBuffer.MODE.EVICT
14
+		: JSMpeg.BitBuffer.MODE.EXPAND;
15
+
16
+	this.sampleRate = 0;
17
+};
18
+
19
+MP2WASM.prototype = Object.create(JSMpeg.Decoder.Base.prototype);
20
+MP2WASM.prototype.constructor = MP2WASM;
21
+
22
+MP2WASM.prototype.initializeWasmDecoder = function() {
23
+	if (!this.module.instance) {
24
+		console.warn('JSMpeg: WASM module not compiled yet');
25
+		return;
26
+	}
27
+	this.instance = this.module.instance;
28
+	this.functions = this.module.instance.exports;
29
+	this.decoder = this.functions._mp2_decoder_create(this.bufferSize, this.bufferMode);
30
+};
31
+
32
+MP2WASM.prototype.destroy = function() {
33
+	this.functions._mp2_decoder_destroy(this.decoder);
34
+};
35
+
36
+MP2WASM.prototype.bufferGetIndex = function() {
37
+	return this.functions._mp2_decoder_get_index(this.decoder);
38
+};
39
+
40
+MP2WASM.prototype.bufferSetIndex = function(index) {
41
+	this.functions._mp2_decoder_set_index(this.decoder, index);
42
+};
43
+
44
+MP2WASM.prototype.bufferWrite = function(buffers) {
45
+	if (!this.decoder) {
46
+		this.initializeWasmDecoder();
47
+	}
48
+
49
+	var totalLength = 0;
50
+	for (var i = 0; i < buffers.length; i++) {
51
+		totalLength += buffers[i].length;
52
+	}
53
+
54
+	var ptr = this.functions._mp2_decoder_get_write_ptr(this.decoder, totalLength);
55
+	for (var i = 0; i < buffers.length; i++) {
56
+		this.instance.heapU8.set(buffers[i], ptr);
57
+		ptr += buffers[i].length;
58
+	}
59
+	
60
+	this.functions._mp2_decoder_did_write(this.decoder, totalLength);
61
+	return totalLength;
62
+};
63
+
64
+MP2WASM.prototype.decode = function() {
65
+	if (!this.decoder) { return; }
66
+	
67
+	var decodedBytes = this.functions._mp2_decoder_decode(this.decoder);
68
+
69
+	if (decodedBytes === 0) {
70
+		return false;
71
+	}
72
+
73
+	if (!this.sampleRate) {
74
+		this.sampleRate = this.functions._mp2_decoder_get_sample_rate(this.decoder);
75
+	}
76
+
77
+	if (this.destination) {
78
+		// Create a Float32 View into the modules output channel data
79
+		var leftPtr = this.functions._mp2_decoder_get_left_channel_ptr(this.decoder),
80
+			rightPtr = this.functions._mp2_decoder_get_right_channel_ptr(this.decoder);
81
+
82
+		var leftOffset = leftPtr / Float32Array.BYTES_PER_ELEMENT,
83
+			rightOffset = rightPtr / Float32Array.BYTES_PER_ELEMENT;
84
+
85
+		var left = this.instance.heapF32.subarray(leftOffset, leftOffset + MP2WASM.SAMPLES_PER_FRAME),
86
+			right = this.instance.heapF32.subarray(rightOffset, rightOffset + MP2WASM.SAMPLES_PER_FRAME);
87
+
88
+		this.destination.play(this.sampleRate, left, right);
89
+	}
90
+
91
+	this.advanceDecodedTime(MP2WASM.SAMPLES_PER_FRAME / this.sampleRate);
92
+	return true;
93
+};
94
+
95
+
96
+MP2WASM.prototype.getCurrentTime = function() {
97
+	var enqueuedTime = this.destination ? this.destination.enqueuedTime : 0;
98
+	return this.decodedTime - enqueuedTime;
99
+};
100
+
101
+MP2WASM.SAMPLES_PER_FRAME = 1152;
102
+
103
+return MP2WASM;
104
+
105
+})();
106
+

+ 115 - 0
src/mpeg1-wasm.js Näytä tiedosto

@@ -0,0 +1,115 @@
1
+JSMpeg.Decoder.MPEG1VideoWASM = (function(){ "use strict";
2
+
3
+var MPEG1WASM = function(options) {
4
+	JSMpeg.Decoder.Base.call(this, options);
5
+
6
+	this.module = options.wasmModule;
7
+
8
+	this.bufferSize = options.videoBufferSize || 512*1024;
9
+	this.bufferMode = options.streaming
10
+		? JSMpeg.BitBuffer.MODE.EVICT
11
+		: JSMpeg.BitBuffer.MODE.EXPAND;
12
+
13
+	this.decodeFirstFrame = options.decodeFirstFrame !== false;
14
+	this.hasSequenceHeader = false;
15
+};
16
+
17
+MPEG1WASM.prototype = Object.create(JSMpeg.Decoder.Base.prototype);
18
+MPEG1WASM.prototype.constructor = MPEG1WASM;
19
+
20
+MPEG1WASM.prototype.initializeWasmDecoder = function() {
21
+	if (!this.module.instance) {
22
+		console.warn('JSMpeg: WASM module not compiled yet');
23
+		return;
24
+	}
25
+	this.instance = this.module.instance;
26
+	this.functions = this.module.instance.exports;
27
+	this.decoder = this.functions._mpeg1_decoder_create(this.bufferSize, this.bufferMode);
28
+};
29
+
30
+MPEG1WASM.prototype.destroy = function() {
31
+	this.functions._mpeg1_decoder_destroy(this.decoder);
32
+};
33
+
34
+MPEG1WASM.prototype.bufferGetIndex = function() {
35
+	return this.functions._mpeg1_decoder_get_index(this.decoder);
36
+};
37
+
38
+MPEG1WASM.prototype.bufferSetIndex = function(index) {
39
+	this.functions._mpeg1_decoder_set_index(this.decoder, index);
40
+};
41
+
42
+MPEG1WASM.prototype.bufferWrite = function(buffers) {
43
+	if (!this.decoder) {
44
+		this.initializeWasmDecoder();
45
+	}
46
+
47
+	var totalLength = 0;
48
+	for (var i = 0; i < buffers.length; i++) {
49
+		totalLength += buffers[i].length;
50
+	}
51
+
52
+	var ptr = this.functions._mpeg1_decoder_get_write_ptr(this.decoder, totalLength);
53
+	for (var i = 0; i < buffers.length; i++) {
54
+		this.instance.heapU8.set(buffers[i], ptr);
55
+		ptr += buffers[i].length;
56
+	}
57
+	
58
+	this.functions._mpeg1_decoder_did_write(this.decoder, totalLength);
59
+	return totalLength;
60
+};
61
+
62
+MPEG1WASM.prototype.write = function(pts, buffers) {
63
+	JSMpeg.Decoder.Base.prototype.write.call(this, pts, buffers);
64
+
65
+	if (!this.hasSequenceHeader && this.functions._mpeg1_decoder_has_sequence_header(this.decoder)) {
66
+		this.loadSequnceHeader();
67
+	}
68
+};
69
+
70
+MPEG1WASM.prototype.loadSequnceHeader = function() {
71
+	this.hasSequenceHeader = true;
72
+	this.frameRate = this.functions._mpeg1_decoder_get_frame_rate(this.decoder);
73
+	this.codedSize = this.functions._mpeg1_decoder_get_coded_size(this.decoder);
74
+
75
+	if (this.destination) {
76
+		var w = this.functions._mpeg1_decoder_get_width(this.decoder);
77
+		var h = this.functions._mpeg1_decoder_get_height(this.decoder);
78
+		this.destination.resize(w, h);
79
+	}
80
+
81
+	if (this.decodeFirstFrame) {
82
+		this.decode();
83
+	}
84
+};
85
+
86
+MPEG1WASM.prototype.decode = function() {
87
+	if (!this.decoder) { return; }
88
+	
89
+	var didDecode = this.functions._mpeg1_decoder_decode(this.decoder);
90
+
91
+	if (!didDecode) {
92
+		return false;
93
+	}
94
+
95
+	// Invoke decode callbacks
96
+	if (this.destination) {
97
+		var ptrY = this.functions._mpeg1_decoder_get_y_ptr(this.decoder),
98
+			ptrCr = this.functions._mpeg1_decoder_get_cr_ptr(this.decoder),
99
+			ptrCb = this.functions._mpeg1_decoder_get_cb_ptr(this.decoder);
100
+
101
+		var dy = this.instance.heapU8.subarray(ptrY, ptrY + this.codedSize);
102
+		var dcr = this.instance.heapU8.subarray(ptrCr, ptrCr + (this.codedSize >> 2));
103
+		var dcb = this.instance.heapU8.subarray(ptrCb, ptrCb + (this.codedSize >> 2));
104
+
105
+		this.destination.render(dy, dcr, dcb, false);
106
+	}
107
+
108
+	this.advanceDecodedTime(1/this.frameRate);
109
+	return true;
110
+};
111
+
112
+return MPEG1WASM;
113
+
114
+})();
115
+

+ 36 - 5
src/player.js Näytä tiedosto

@@ -27,17 +27,28 @@ var Player = function(url, options) {
27 27
 	this.demuxer = new JSMpeg.Demuxer.TS(options);
28 28
 	this.source.connect(this.demuxer);
29 29
 
30
+	if (!options.disableWebAssembly && JSMpeg.WASMModule.IsSupported()) {
31
+		this.wasmModule = new JSMpeg.WASMModule();
32
+		options.wasmModule =this.wasmModule;
33
+	}
34
+
30 35
 	if (options.video !== false) {
31
-		this.video = new JSMpeg.Decoder.MPEG1Video(options);
36
+		this.video = options.wasmModule
37
+			? new JSMpeg.Decoder.MPEG1VideoWASM(options)
38
+			: new JSMpeg.Decoder.MPEG1Video(options);
39
+
32 40
 		this.renderer = !options.disableGl && JSMpeg.Renderer.WebGL.IsSupported()
33 41
 			? new JSMpeg.Renderer.WebGL(options)
34 42
 			: new JSMpeg.Renderer.Canvas2D(options);
43
+		
35 44
 		this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.VIDEO_1, this.video);
36 45
 		this.video.connect(this.renderer);
37 46
 	}
38 47
 
39 48
 	if (options.audio !== false && JSMpeg.AudioOutput.WebAudio.IsSupported()) {
40
-		this.audio = new JSMpeg.Decoder.MP2Audio(options);
49
+		this.audio = options.wasmModule
50
+			? new JSMpeg.Decoder.MP2AudioWASM(options)
51
+			: new JSMpeg.Decoder.MP2Audio(options);
41 52
 		this.audioOut = new JSMpeg.AudioOutput.WebAudio(options);
42 53
 		this.demuxer.connect(JSMpeg.Demuxer.TS.STREAM.AUDIO_1, this.audio);
43 54
 		this.audio.connect(this.audioOut);
@@ -57,8 +68,26 @@ var Player = function(url, options) {
57 68
 		document.addEventListener('visibilitychange', this.showHide.bind(this));
58 69
 	}
59 70
 
60
-	this.source.start();
71
+	// If we have WebAssembly support, wait until the module is compiled before
72
+	// loading the source. Otherwise the decoders won't know what to do with 
73
+	// the source data.
74
+	if (this.wasmModule) {
75
+		if (JSMpeg.WASM_BINARY_INLINED) {
76
+			var wasm = JSMpeg.Base64ToArrayBuffer(JSMpeg.WASM_BINARY_INLINED);
77
+			this.wasmModule.loadFromBuffer(wasm, this.startLoading.bind(this));
78
+		}
79
+		else {
80
+			this.wasmModule.loadFromFile('jsmpeg.wasm',  this.startLoading.bind(this));
81
+		}
82
+	}
83
+	else {
84
+		this.startLoading();
85
+		
86
+	}
87
+};
61 88
 
89
+Player.prototype.startLoading = function() {
90
+	this.source.start();
62 91
 	if (this.autoplay) {
63 92
 		this.play();
64 93
 	}
@@ -113,8 +142,10 @@ Player.prototype.stop = function(ev) {
113 142
 Player.prototype.destroy = function() {
114 143
 	this.pause();
115 144
 	this.source.destroy();
116
-	this.renderer.destroy();
117
-	this.audioOut.destroy();
145
+	this.video && this.video.destroy();
146
+	this.renderer && this.renderer.destroy();
147
+	this.audio && this.audio.destroy();
148
+	this.audioOut && this.audioOut.destroy();
118 149
 };
119 150
 
120 151
 Player.prototype.seek = function(time) {

+ 148 - 0
src/wasm-module.js Näytä tiedosto

@@ -0,0 +1,148 @@
1
+JSMpeg.WASMModule = (function(){ "use strict";
2
+
3
+var WASM = function() {
4
+	this.stackSize = 5 * 1024 * 1024; // emscripten default
5
+	this.pageSize = 64 * 1024; // wasm page size
6
+	this.onInitCallback = null;
7
+};
8
+
9
+WASM.prototype.write = function(buffer) {
10
+	this.loadFromBuffer(buffer, this.onInitCallback);
11
+};
12
+
13
+WASM.prototype.loadFromFile = function(url, callback) {
14
+	this.onInitCallback = callback;
15
+	var ajax = new JSMpeg.Source.Ajax(url);
16
+	ajax.connect(this);
17
+	ajax.start();
18
+};
19
+
20
+WASM.prototype.loadFromBuffer = function(buffer, callback) {
21
+	this.moduleInfo = this.readDylinkSection(buffer);
22
+	if (!this.moduleInfo) {
23
+		this.callback && this.callback(null);
24
+		return;
25
+	}
26
+
27
+	this.memory = new WebAssembly.Memory({initial: 256});
28
+	var env = {
29
+		memory: this.memory,
30
+		memoryBase: 0,
31
+		table: new WebAssembly.Table({initial: this.moduleInfo.tableSize, element: 'anyfunc'}),
32
+		tableBase: 0,
33
+		abort: this.c_abort.bind(this),
34
+		___assert_fail: this.c_assertFail.bind(this),
35
+		_sbrk: this.c_sbrk.bind(this)
36
+	};
37
+
38
+	this.brk = this.align(this.moduleInfo.memorySize + this.stackSize);
39
+	WebAssembly.instantiate(buffer, {env: env}).then(function(results){
40
+		this.instance = results.instance;
41
+		if (this.instance.exports.__post_instantiate) {
42
+			this.instance.exports.__post_instantiate();
43
+		}
44
+		this.createHeapViews();
45
+		callback && callback(this);
46
+	}.bind(this))
47
+};
48
+
49
+WASM.prototype.createHeapViews = function() {
50
+	this.instance.heapU8 = new Uint8Array(this.memory.buffer);
51
+	this.instance.heapU32 = new Uint32Array(this.memory.buffer);
52
+	this.instance.heapF32 = new Float32Array(this.memory.buffer);
53
+};
54
+
55
+WASM.prototype.align = function(addr) {
56
+	var a = Math.pow(2, this.moduleInfo.memoryAlignment);
57
+	return Math.ceil(addr / a) * a;
58
+};
59
+
60
+WASM.prototype.c_sbrk = function(size) {
61
+	var previousBrk = this.brk;
62
+	this.brk += size;
63
+
64
+	if (this.brk > this.memory.buffer.byteLength) {
65
+		var bytesNeeded = this.brk - this.memory.buffer.byteLength;
66
+		var pagesNeeded = Math.ceil(bytesNeeded / this.pageSize);
67
+		this.memory.grow(pagesNeeded);
68
+		this.createHeapViews();
69
+	}
70
+	return previousBrk;
71
+};
72
+
73
+WASM.prototype.c_abort = function(size) {
74
+	console.warn('JSMPeg: WASM abort', arguments);
75
+};
76
+
77
+WASM.prototype.c_assertFail = function(size) {
78
+	console.warn('JSMPeg: WASM ___assert_fail', arguments);
79
+};
80
+
81
+
82
+WASM.prototype.readDylinkSection = function(buffer) {
83
+	// Read the WASM header and dylink section of the .wasm binary data
84
+	// to get the needed table size and static data size.
85
+
86
+	// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
87
+	// https://github.com/kripken/emscripten/blob/20602efb955a7c6c20865a495932427e205651d2/src/support.js
88
+
89
+	var bytes = new Uint8Array(buffer);
90
+	var next = 0;
91
+
92
+	var readVarUint = function () {
93
+		var ret = 0;
94
+		var mul = 1;
95
+		while (1) {
96
+			var byte = bytes[next++];
97
+			ret += ((byte & 0x7f) * mul);
98
+			mul *= 0x80;
99
+			if (!(byte & 0x80)) {
100
+				return ret
101
+			}
102
+		}
103
+	}
104
+
105
+	var matchNextBytes = function(expected) {
106
+		for (var i = 0; i < expected.length; i++) {
107
+			var b = typeof(expected[i]) === 'string' 
108
+				? expected[i].charCodeAt(0)
109
+				: expected[i];
110
+			if (bytes[next++] !== b) {
111
+				return false;
112
+			}
113
+		}
114
+		return true;
115
+	};
116
+
117
+	
118
+
119
+	// Make sure we have a wasm header
120
+	if (!matchNextBytes([0, 'a', 's', 'm'])) {
121
+		console.warn('JSMpeg: WASM header not found');
122
+		return null;
123
+	}
124
+
125
+	// Make sure we have a dylink section
126
+	var next = 9;
127
+	var sectionSize = readVarUint();
128
+	if (!matchNextBytes([6, 'd', 'y', 'l', 'i', 'n', 'k'])) {
129
+		console.warn('JSMpeg: No dylink section found in WASM');
130
+		return null;
131
+	}
132
+
133
+	return {
134
+		memorySize: readVarUint(),
135
+		memoryAlignment: readVarUint(),
136
+		tableSize: readVarUint(),
137
+		tableAlignment: readVarUint()
138
+	};
139
+};
140
+
141
+WASM.IsSupported = function() {
142
+	return (!!window.WebAssembly);
143
+};
144
+
145
+return WASM;
146
+
147
+})();
148
+

+ 189 - 0
src/wasm/buffer.c Näytä tiedosto

@@ -0,0 +1,189 @@
1
+#include <string.h>
2
+#include <stdbool.h>
3
+#include <stdlib.h>
4
+
5
+#include "buffer.h"
6
+
7
+typedef struct bit_buffer_t {
8
+	uint8_t *bytes;
9
+	unsigned int index;
10
+	unsigned int byte_capacity;
11
+	unsigned int byte_length;
12
+	bit_buffer_mode_t mode;
13
+} bit_buffer_t;
14
+
15
+void bit_buffer_resize(bit_buffer_t *self, unsigned int byte_capacity);
16
+void bit_buffer_evict(bit_buffer_t *self, unsigned int bytes_needed);
17
+
18
+
19
+
20
+bit_buffer_t *bit_buffer_create(unsigned int initial_byte_capacity, bit_buffer_mode_t mode) {
21
+	bit_buffer_t *self = malloc(sizeof(bit_buffer_t));
22
+	self->mode = mode;
23
+	self->bytes = malloc(initial_byte_capacity);
24
+	self->byte_capacity = initial_byte_capacity;
25
+	self->byte_length = 0;
26
+	self->index = 0;
27
+	return self;
28
+}
29
+
30
+
31
+void bit_buffer_destroy(bit_buffer_t *self) {
32
+	free(self->bytes);
33
+	free(self);
34
+}
35
+
36
+
37
+int bit_buffer_get_index(bit_buffer_t *self) {
38
+	return self->index;
39
+}
40
+
41
+
42
+void bit_buffer_set_index(bit_buffer_t *self, unsigned int index) {
43
+	self->index = index; // TODO check validity!
44
+}
45
+
46
+
47
+uint8_t *bit_buffer_get_write_ptr(bit_buffer_t *self, unsigned int bytes_to_write) {
48
+	int bytes_available = self->byte_capacity - self->byte_length;
49
+
50
+	if (bytes_to_write > bytes_available) {
51
+		if (self->mode == BIT_BUFFER_MODE_EXPAND) {
52
+			int new_byte_capacity = self->byte_capacity * 2;
53
+			if (new_byte_capacity + bytes_available < bytes_to_write) {
54
+				new_byte_capacity = bytes_to_write - bytes_available;
55
+			}
56
+			bit_buffer_resize(self, new_byte_capacity);
57
+		}
58
+		else {
59
+			bit_buffer_evict(self, bytes_to_write);
60
+		}
61
+	}
62
+
63
+	return self->bytes + self->byte_length;
64
+};
65
+
66
+
67
+void bit_buffer_did_write(bit_buffer_t *self, unsigned int bytes_written) {
68
+	self->byte_length += bytes_written;
69
+}
70
+
71
+
72
+int bit_buffer_find_next_start_code(bit_buffer_t *self) {
73
+	for (int i = ((self->index + 7) >> 3); i < self->byte_length; i++) {
74
+		if(
75
+			self->bytes[i] == 0x00 &&
76
+			self->bytes[i+1] == 0x00 &&
77
+			self->bytes[i+2] == 0x01
78
+		) {
79
+			self->index = (i+4) << 3;
80
+			return self->bytes[i+3];
81
+		}
82
+	}
83
+	self->index = (self->byte_length << 3);
84
+	return -1;
85
+}
86
+
87
+
88
+int bit_buffer_find_start_code(bit_buffer_t *self, int code) {
89
+	int current = 0;
90
+	while (true) {
91
+		current = bit_buffer_find_next_start_code(self);
92
+		if (current == code || current == -1) {
93
+			return current;
94
+		}
95
+	}
96
+	return -1;
97
+}
98
+
99
+
100
+int bit_buffer_next_bytes_are_start_code(bit_buffer_t *self) {
101
+	int i = ((self->index + 7) >> 3);
102
+	return (
103
+		i >= self->byte_length || (
104
+			self->bytes[i] == 0x00 && 
105
+			self->bytes[i+1] == 0x00 &&
106
+			self->bytes[i+2] == 0x01
107
+		)
108
+	);
109
+}
110
+
111
+
112
+int bit_buffer_peek(bit_buffer_t *self, unsigned int count) {
113
+	int offset = self->index;
114
+	int value = 0;
115
+	while (count) {
116
+		int current_byte = self->bytes[offset >> 3];
117
+		int remaining = 8 - (offset & 7); // remaining bits in byte
118
+		int read = remaining < count ? remaining : count; // bits in self run
119
+		int shift = remaining - read;
120
+		int mask = (0xff >> (8-read));
121
+
122
+		value = (value << read) | ((current_byte & (mask << shift)) >> shift);
123
+
124
+		offset += read;
125
+		count -= read;
126
+	}
127
+
128
+	return value;
129
+}
130
+
131
+
132
+int bit_buffer_read(bit_buffer_t *self, unsigned int count) {
133
+	int value = bit_buffer_peek(self, count);
134
+	self->index += count;
135
+	return value;
136
+}
137
+
138
+
139
+int bit_buffer_skip(bit_buffer_t *self, unsigned int count) {
140
+	return (self->index += count);
141
+}
142
+
143
+
144
+void bit_buffer_rewind(bit_buffer_t *self, unsigned int count) {
145
+	self->index = self->index - count;
146
+	if (self->index < 0) {
147
+		self->index = 0;
148
+	}
149
+}
150
+
151
+
152
+int bit_buffer_has(bit_buffer_t *self, unsigned int count) {
153
+	return ((self->byte_length << 3) - self->index) >= count;
154
+}
155
+
156
+
157
+void bit_buffer_resize(bit_buffer_t *self, unsigned int byte_capacity) {
158
+	self->bytes = realloc(self->bytes, byte_capacity);
159
+	self->byte_capacity = byte_capacity;
160
+	if (self->index > self->byte_length << 3) {
161
+		self->index = self->byte_length << 3;
162
+	}
163
+}
164
+
165
+
166
+void bit_buffer_evict(bit_buffer_t *self, unsigned int bytes_needed) {
167
+	int byte_pos = self->index >> 3;
168
+	int bytes_available = self->byte_capacity - self->byte_length;
169
+	
170
+	// If the current index is the write position, we can simply reset both
171
+	// to 0. Also reset (and throw away yet unread data) if we won't be able
172
+	// to fit the new data in even after a normal eviction.
173
+	if (
174
+		byte_pos == self->byte_length ||
175
+		bytes_needed > bytes_available + byte_pos // emergency evac
176
+	) {
177
+		self->byte_length = 0;
178
+		self->index = 0;
179
+		return;
180
+	}
181
+	else if (byte_pos == 0) {
182
+		// Nothing read yet - we can't evict anything
183
+		return;
184
+	}
185
+
186
+	memmove(self->bytes, self->bytes + byte_pos, self->byte_length - byte_pos);
187
+	self->byte_length -= byte_pos;
188
+	self->index -= byte_pos << 3;
189
+}

+ 31 - 0
src/wasm/buffer.h Näytä tiedosto

@@ -0,0 +1,31 @@
1
+#ifndef BUFFER_H
2
+#define BUFFER_H
3
+
4
+#include <stdint.h>
5
+
6
+typedef struct bit_buffer_t bit_buffer_t;
7
+
8
+typedef enum {
9
+	BIT_BUFFER_MODE_EVICT = 1,
10
+	BIT_BUFFER_MODE_EXPAND = 2
11
+} bit_buffer_mode_t;
12
+
13
+
14
+bit_buffer_t *bit_buffer_create(unsigned int initial_byte_capacity, bit_buffer_mode_t mode);
15
+void bit_buffer_destroy(bit_buffer_t *self);
16
+
17
+int bit_buffer_get_index(bit_buffer_t *self);
18
+void bit_buffer_set_index(bit_buffer_t *self, unsigned int index);
19
+
20
+uint8_t *bit_buffer_get_write_ptr(bit_buffer_t *self, unsigned int bytes_to_write);
21
+void bit_buffer_did_write(bit_buffer_t *self, unsigned int bytes_written);
22
+int bit_buffer_find_next_start_code(bit_buffer_t *self);
23
+int bit_buffer_find_start_code(bit_buffer_t *self, int code);
24
+int bit_buffer_next_bytes_are_start_code(bit_buffer_t *self);
25
+int bit_buffer_peek(bit_buffer_t *self, unsigned int count);
26
+int bit_buffer_read(bit_buffer_t *self, unsigned int count);
27
+int bit_buffer_skip(bit_buffer_t *self, unsigned int count);
28
+int bit_buffer_has(bit_buffer_t *self, unsigned int count);
29
+void bit_buffer_rewind(bit_buffer_t *self, unsigned int count);
30
+
31
+#endif

+ 703 - 0
src/wasm/mp2.c Näytä tiedosto

@@ -0,0 +1,703 @@
1
+#include <string.h>
2
+#include <stdlib.h>
3
+#include "mp2.h"
4
+
5
+const static int FRAME_SYNC = 0x7ff;
6
+
7
+const static int VERSION_MPEG_2_5 = 0x0;
8
+const static int VERSION_MPEG_2 = 0x2;
9
+const static int VERSION_MPEG_1 = 0x3;
10
+
11
+const static int LAYER_III = 0x1;
12
+const static int LAYER_II = 0x2;
13
+const static int LAYER_I = 0x3;
14
+
15
+const static int MODE_STEREO = 0x0;
16
+const static int MODE_JOINT_STEREO = 0x1;
17
+const static int MODE_DUAL_CHANNEL = 0x2;
18
+const static int MODE_MONO = 0x3;
19
+
20
+const static unsigned short SAMPLE_RATE[] = {
21
+	44100, 48000, 32000, 0, // MPEG-1
22
+	22050, 24000, 16000, 0  // MPEG-2
23
+};
24
+
25
+const static short BIT_RATE[] = {
26
+	32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, // MPEG-1
27
+	 8, 16, 24, 32, 40, 48,  56,  64,  80,  96, 112, 128, 144, 160  // MPEG-2
28
+};
29
+
30
+const static int SCALEFACTOR_BASE[] = {
31
+	0x02000000, 0x01965FEA, 0x01428A30
32
+};
33
+
34
+const static float SYNTHESIS_WINDOW[] = {
35
+	     0.0,     -0.5,     -0.5,     -0.5,     -0.5,     -0.5,
36
+	    -0.5,     -1.0,     -1.0,     -1.0,     -1.0,     -1.5,
37
+	    -1.5,     -2.0,     -2.0,     -2.5,     -2.5,     -3.0,
38
+	    -3.5,     -3.5,     -4.0,     -4.5,     -5.0,     -5.5,
39
+	    -6.5,     -7.0,     -8.0,     -8.5,     -9.5,    -10.5,
40
+	   -12.0,    -13.0,    -14.5,    -15.5,    -17.5,    -19.0,
41
+	   -20.5,    -22.5,    -24.5,    -26.5,    -29.0,    -31.5,
42
+	   -34.0,    -36.5,    -39.5,    -42.5,    -45.5,    -48.5,
43
+	   -52.0,    -55.5,    -58.5,    -62.5,    -66.0,    -69.5,
44
+	   -73.5,    -77.0,    -80.5,    -84.5,    -88.0,    -91.5,
45
+	   -95.0,    -98.0,   -101.0,   -104.0,    106.5,    109.0,
46
+	   111.0,    112.5,    113.5,    114.0,    114.0,    113.5,
47
+	   112.0,    110.5,    107.5,    104.0,    100.0,     94.5,
48
+	    88.5,     81.5,     73.0,     63.5,     53.0,     41.5,
49
+	    28.5,     14.5,     -1.0,    -18.0,    -36.0,    -55.5,
50
+	   -76.5,    -98.5,   -122.0,   -147.0,   -173.5,   -200.5,
51
+	  -229.5,   -259.5,   -290.5,   -322.5,   -355.5,   -389.5,
52
+	  -424.0,   -459.5,   -495.5,   -532.0,   -568.5,   -605.0,
53
+	  -641.5,   -678.0,   -714.0,   -749.0,   -783.5,   -817.0,
54
+	  -849.0,   -879.5,   -908.5,   -935.0,   -959.5,   -981.0,
55
+	 -1000.5,  -1016.0,  -1028.5,  -1037.5,  -1042.5,  -1043.5,
56
+	 -1040.0,  -1031.5,   1018.5,   1000.0,    976.0,    946.5,
57
+	   911.0,    869.5,    822.0,    767.5,    707.0,    640.0,
58
+	   565.5,    485.0,    397.0,    302.5,    201.0,     92.5,
59
+	   -22.5,   -144.0,   -272.5,   -407.0,   -547.5,   -694.0,
60
+	  -846.0,  -1003.0,  -1165.0,  -1331.5,  -1502.0,  -1675.5,
61
+	 -1852.5,  -2031.5,  -2212.5,  -2394.0,  -2576.5,  -2758.5,
62
+	 -2939.5,  -3118.5,  -3294.5,  -3467.5,  -3635.5,  -3798.5,
63
+	 -3955.0,  -4104.5,  -4245.5,  -4377.5,  -4499.0,  -4609.5,
64
+	 -4708.0,  -4792.5,  -4863.5,  -4919.0,  -4958.0,  -4979.5,
65
+	 -4983.0,  -4967.5,  -4931.5,  -4875.0,  -4796.0,  -4694.5,
66
+	 -4569.5,  -4420.0,  -4246.0,  -4046.0,  -3820.0,  -3567.0,
67
+	  3287.0,   2979.5,   2644.0,   2280.5,   1888.0,   1467.5,
68
+	  1018.5,    541.0,     35.0,   -499.0,  -1061.0,  -1650.0,
69
+	 -2266.5,  -2909.0,  -3577.0,  -4270.0,  -4987.5,  -5727.5,
70
+	 -6490.0,  -7274.0,  -8077.5,  -8899.5,  -9739.0, -10594.5,
71
+	-11464.5, -12347.0, -13241.0, -14144.5, -15056.0, -15973.5,
72
+	-16895.5, -17820.0, -18744.5, -19668.0, -20588.0, -21503.0,
73
+	-22410.5, -23308.5, -24195.0, -25068.5, -25926.5, -26767.0,
74
+	-27589.0, -28389.0, -29166.5, -29919.0, -30644.5, -31342.0,
75
+	-32009.5, -32645.0, -33247.0, -33814.5, -34346.0, -34839.5,
76
+	-35295.0, -35710.0, -36084.5, -36417.5, -36707.5, -36954.0,
77
+	-37156.5, -37315.0, -37428.0, -37496.0,  37519.0,  37496.0,
78
+	 37428.0,  37315.0,  37156.5,  36954.0,  36707.5,  36417.5,
79
+	 36084.5,  35710.0,  35295.0,  34839.5,  34346.0,  33814.5,
80
+	 33247.0,  32645.0,  32009.5,  31342.0,  30644.5,  29919.0,
81
+	 29166.5,  28389.0,  27589.0,  26767.0,  25926.5,  25068.5,
82
+	 24195.0,  23308.5,  22410.5,  21503.0,  20588.0,  19668.0,
83
+	 18744.5,  17820.0,  16895.5,  15973.5,  15056.0,  14144.5,
84
+	 13241.0,  12347.0,  11464.5,  10594.5,   9739.0,   8899.5,
85
+	  8077.5,   7274.0,   6490.0,   5727.5,   4987.5,   4270.0,
86
+	  3577.0,   2909.0,   2266.5,   1650.0,   1061.0,    499.0,
87
+	   -35.0,   -541.0,  -1018.5,  -1467.5,  -1888.0,  -2280.5,
88
+	 -2644.0,  -2979.5,   3287.0,   3567.0,   3820.0,   4046.0,
89
+	  4246.0,   4420.0,   4569.5,   4694.5,   4796.0,   4875.0,
90
+	  4931.5,   4967.5,   4983.0,   4979.5,   4958.0,   4919.0,
91
+	  4863.5,   4792.5,   4708.0,   4609.5,   4499.0,   4377.5,
92
+	  4245.5,   4104.5,   3955.0,   3798.5,   3635.5,   3467.5,
93
+	  3294.5,   3118.5,   2939.5,   2758.5,   2576.5,   2394.0,
94
+	  2212.5,   2031.5,   1852.5,   1675.5,   1502.0,   1331.5,
95
+	  1165.0,   1003.0,    846.0,    694.0,    547.5,    407.0,
96
+	   272.5,    144.0,     22.5,    -92.5,   -201.0,   -302.5,
97
+	  -397.0,   -485.0,   -565.5,   -640.0,   -707.0,   -767.5,
98
+	  -822.0,   -869.5,   -911.0,   -946.5,   -976.0,  -1000.0,
99
+	  1018.5,   1031.5,   1040.0,   1043.5,   1042.5,   1037.5,
100
+	  1028.5,   1016.0,   1000.5,    981.0,    959.5,    935.0,
101
+	   908.5,    879.5,    849.0,    817.0,    783.5,    749.0,
102
+	   714.0,    678.0,    641.5,    605.0,    568.5,    532.0,
103
+	   495.5,    459.5,    424.0,    389.5,    355.5,    322.5,
104
+	   290.5,    259.5,    229.5,    200.5,    173.5,    147.0,
105
+	   122.0,     98.5,     76.5,     55.5,     36.0,     18.0,
106
+		1.0,    -14.5,    -28.5,    -41.5,    -53.0,    -63.5,
107
+	   -73.0,    -81.5,    -88.5,    -94.5,   -100.0,   -104.0,
108
+	  -107.5,   -110.5,   -112.0,   -113.5,   -114.0,   -114.0,
109
+	  -113.5,   -112.5,   -111.0,   -109.0,    106.5,    104.0,
110
+	   101.0,     98.0,     95.0,     91.5,     88.0,     84.5,
111
+	    80.5,     77.0,     73.5,     69.5,     66.0,     62.5,
112
+	    58.5,     55.5,     52.0,     48.5,     45.5,     42.5,
113
+	    39.5,     36.5,     34.0,     31.5,     29.0,     26.5,
114
+	    24.5,     22.5,     20.5,     19.0,     17.5,     15.5,
115
+	    14.5,     13.0,     12.0,     10.5,      9.5,      8.5,
116
+	     8.0,      7.0,      6.5,      5.5,      5.0,      4.5,
117
+	     4.0,      3.5,      3.5,      3.0,      2.5,      2.5,
118
+	     2.0,      2.0,      1.5,      1.5,      1.0,      1.0,
119
+	     1.0,      1.0,      0.5,      0.5,      0.5,      0.5,
120
+	     0.5,      0.5
121
+};
122
+
123
+// Quantizer lookup, step 1: bitrate classes
124
+const static uint8_t QUANT_LUT_STEP_1[2][16] = {
125
+ 	// 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384 <- bitrate
126
+	{   0,  0,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2}, // mono
127
+	// 16, 24, 28, 32, 40, 48, 56, 64, 80, 96,112,128,160,192 <- bitrate / chan
128
+	{   0,  0,  0,  0,  0,  0,  1,  1,  1,  2,  2,  2,  2,  2} // stereo
129
+};
130
+
131
+// Quantizer lookup, step 2: bitrate class, sample rate -> B2 table idx, sblimit
132
+const static uint8_t QUANT_TAB_A = (27 | 64);   // Table 3-B.2a: high-rate, sblimit = 27
133
+const static uint8_t QUANT_TAB_B = (30 | 64);   // Table 3-B.2b: high-rate, sblimit = 30
134
+const static uint8_t QUANT_TAB_C =   8;         // Table 3-B.2c:  low-rate, sblimit =  8
135
+const static uint8_t QUANT_TAB_D =  12;         // Table 3-B.2d:  low-rate, sblimit = 12
136
+
137
+const static uint8_t QUANT_LUT_STEP_2[3][3] = {
138
+	// 44.1 kHz,    48 kHz,      32 kHz
139
+	{QUANT_TAB_C, QUANT_TAB_C, QUANT_TAB_D}, // 32 - 48 kbit/sec/ch
140
+	{QUANT_TAB_A, QUANT_TAB_A, QUANT_TAB_A}, // 56 - 80 kbit/sec/ch
141
+	{QUANT_TAB_B, QUANT_TAB_A, QUANT_TAB_B}  // 96+	 kbit/sec/ch
142
+};
143
+
144
+// Quantizer lookup, step 3: B2 table, subband -> nbal, row index
145
+// (upper 4 bits: nbal, lower 4 bits: row index)
146
+const static uint8_t QUANT_LUT_STEP_3[3][32] = {
147
+	// Low-rate table (3-B.2c and 3-B.2d)
148
+	{
149
+		0x44,0x44,
150
+	  	0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34
151
+	},
152
+	// High-rate table (3-B.2a and 3-B.2b)
153
+	{
154
+		0x43,0x43,0x43,
155
+		0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,
156
+		0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,
157
+		0x20,0x20,0x20,0x20,0x20,0x20,0x20
158
+	},
159
+	// MPEG-2 LSR table (B.2 in ISO 13818-3)
160
+	{
161
+		0x45,0x45,0x45,0x45,
162
+		0x34,0x34,0x34,0x34,0x34,0x34,0x34,
163
+		0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
164
+					   0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24	
165
+	}
166
+};
167
+
168
+// Quantizer lookup, step 4: table row, allocation[] value -> quant table index
169
+const static uint8_t QUANT_LUT_STEP4[6][16] = {
170
+	{0, 1, 2, 17},
171
+	{0, 1, 2, 3, 4, 5, 6, 17},
172
+	{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17},
173
+	{0, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17},
174
+	{0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17},
175
+	{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
176
+};
177
+
178
+typedef struct quantizer_spec_t {
179
+	unsigned short levels;
180
+	unsigned char group;
181
+	unsigned char bits;
182
+} quantizer_spec_t;
183
+
184
+const static quantizer_spec_t QUANT_TAB[] = {
185
+	{.levels =     3, .group = 1, .bits =  5},  //  1
186
+	{.levels =     5, .group = 1, .bits =  7},  //  2
187
+	{.levels =     7, .group = 0, .bits =  3},  //  3
188
+	{.levels =     9, .group = 1, .bits = 10},  //  4
189
+	{.levels =    15, .group = 0, .bits =  4},  //  5
190
+	{.levels =    31, .group = 0, .bits =  5},  //  6
191
+	{.levels =    63, .group = 0, .bits =  6},  //  7
192
+	{.levels =   127, .group = 0, .bits =  7},  //  8
193
+	{.levels =   255, .group = 0, .bits =  8},  //  9
194
+	{.levels =   511, .group = 0, .bits =  9},  // 10
195
+	{.levels =  1023, .group = 0, .bits = 10},  // 11
196
+	{.levels =  2047, .group = 0, .bits = 11},  // 12
197
+	{.levels =  4095, .group = 0, .bits = 12},  // 13
198
+	{.levels =  8191, .group = 0, .bits = 13},  // 14
199
+	{.levels = 16383, .group = 0, .bits = 14},  // 15
200
+	{.levels = 32767, .group = 0, .bits = 15},  // 16
201
+	{.levels = 65535, .group = 0, .bits = 16}   // 17
202
+};
203
+
204
+#define SAMPLES_PER_FRAME 1152
205
+
206
+typedef struct mp2_decoder_t {
207
+	int sample_rate;
208
+	int v_pos;
209
+
210
+	bit_buffer_t *bits;
211
+
212
+	const quantizer_spec_t *allocation[2][32];
213
+	uint8_t scale_factor_info[2][32];
214
+	int scale_factor[2][32][3];
215
+	int sample[2][32][3];
216
+
217
+	float channel_left[SAMPLES_PER_FRAME];
218
+	float channel_right[SAMPLES_PER_FRAME];
219
+	float D[1024];
220
+	float V[1024];
221
+	int U[32];
222
+} mp2_decoder_t;
223
+
224
+
225
+void matrix_transform(int s[32][3], int ss, float *d, int dp);
226
+void read_samples(mp2_decoder_t *self, int ch, int sb, int part);
227
+const quantizer_spec_t *read_allocation(mp2_decoder_t *self, int sb, int tab3);
228
+int decode_frame(mp2_decoder_t *self);
229
+
230
+
231
+// -----------------------------------------------------------------------------
232
+// Public interface
233
+
234
+mp2_decoder_t *mp2_decoder_create(unsigned int buffer_size, bit_buffer_mode_t buffer_mode) {
235
+	mp2_decoder_t *self = malloc(sizeof(mp2_decoder_t));
236
+	self->bits = bit_buffer_create(buffer_size, buffer_mode);
237
+
238
+	self->sample_rate = 44100;
239
+	memcpy(self->D, SYNTHESIS_WINDOW, 512 * sizeof(float));
240
+	memcpy(self->D + 512, SYNTHESIS_WINDOW, 512 * sizeof(float));
241
+
242
+	return self;
243
+}
244
+
245
+void mp2_decoder_destroy(mp2_decoder_t *self) {
246
+	bit_buffer_destroy(self->bits);
247
+	free(self);
248
+}
249
+
250
+void *mp2_decoder_get_write_ptr(mp2_decoder_t *self, unsigned int byte_size) {
251
+	return bit_buffer_get_write_ptr(self->bits, byte_size);
252
+}
253
+
254
+int mp2_decoder_get_index(mp2_decoder_t *self) {
255
+	return bit_buffer_get_index(self->bits);
256
+}
257
+
258
+void mp2_decoder_set_index(mp2_decoder_t *self, unsigned int index) {
259
+	bit_buffer_set_index(self->bits, index);
260
+}
261
+
262
+void mp2_decoder_did_write(mp2_decoder_t *self, unsigned int byte_size) {
263
+	bit_buffer_did_write(self->bits, byte_size);
264
+}
265
+
266
+int mp2_decoder_get_sample_rate(mp2_decoder_t *self) {
267
+	return self->sample_rate;
268
+}
269
+
270
+void *mp2_decoder_get_left_channel_ptr(mp2_decoder_t *self) {
271
+	return self->channel_left;
272
+}
273
+
274
+void *mp2_decoder_get_right_channel_ptr(mp2_decoder_t *self) {
275
+	return self->channel_right;
276
+}
277
+
278
+int mp2_decoder_decode(mp2_decoder_t *self) {
279
+	int byte_pos = bit_buffer_get_index(self->bits) >> 3;
280
+
281
+	if (!bit_buffer_has(self->bits, 16)) {
282
+		return 0;
283
+	}
284
+
285
+	int decoded_bytes = decode_frame(self);
286
+	bit_buffer_set_index(self->bits, (byte_pos + decoded_bytes) << 3);
287
+	return decoded_bytes;
288
+}
289
+
290
+
291
+
292
+
293
+int decode_frame(mp2_decoder_t *self) {
294
+	// Check for valid header: syncword OK, MPEG-Audio Layer 2
295
+	int sync = bit_buffer_read(self->bits, 11);
296
+	int version = bit_buffer_read(self->bits, 2);
297
+	int layer = bit_buffer_read(self->bits, 2);
298
+	int hasCRC = !bit_buffer_read(self->bits, 1);
299
+
300
+	if (
301
+		sync != FRAME_SYNC ||
302
+		version != VERSION_MPEG_1 ||
303
+		layer != LAYER_II
304
+	) {
305
+		return 0; // Invalid header or unsupported version
306
+	}
307
+
308
+	int bitrate_index = bit_buffer_read(self->bits, 4) - 1;
309
+	if (bitrate_index > 13) {
310
+		return 0;  // Invalid bit rate or 'free format'
311
+	}
312
+
313
+	int sample_rate_index = bit_buffer_read(self->bits, 2);
314
+	int sample_rate = SAMPLE_RATE[sample_rate_index];
315
+	if (sample_rate_index == 3) {
316
+		return 0; // Invalid sample rate
317
+	}
318
+	if (version == VERSION_MPEG_2) {
319
+		sample_rate_index += 4;
320
+		bitrate_index += 14;
321
+	}
322
+	int padding = bit_buffer_read(self->bits, 1),
323
+		privat = bit_buffer_read(self->bits, 1),
324
+		mode = bit_buffer_read(self->bits, 2);
325
+
326
+	// Parse the mode_extension, set up the stereo bound
327
+	int bound = 0;
328
+	if (mode == MODE_JOINT_STEREO) {
329
+		bound = (bit_buffer_read(self->bits, 2) + 1) << 2;
330
+	}
331
+	else {
332
+		bit_buffer_skip(self->bits, 2);
333
+		bound = (mode == MODE_MONO) ? 0 : 32;
334
+	}
335
+
336
+	// Discard the last 4 bits of the header and the CRC value, if present
337
+	bit_buffer_skip(self->bits, 4);
338
+	if (hasCRC) {
339
+		bit_buffer_skip(self->bits, 16);
340
+	}
341
+
342
+	// Compute the frame size
343
+	int bitrate = BIT_RATE[bitrate_index];
344
+	sample_rate = SAMPLE_RATE[sample_rate_index];
345
+	int frame_size = ((144000 * bitrate / sample_rate) + padding)|0;
346
+	
347
+
348
+	// Prepare the quantizer table lookups
349
+	int tab3 = 0;
350
+	int sblimit = 0;
351
+	if (version == VERSION_MPEG_2) {
352
+		// MPEG-2 (LSR)
353
+		tab3 = 2;
354
+		sblimit = 30;
355
+	}
356
+	else {
357
+		// MPEG-1
358
+		int tab1 = (mode == MODE_MONO) ? 0 : 1;
359
+		int tab2 = QUANT_LUT_STEP_1[tab1][bitrate_index];
360
+		tab3 = QUANT_LUT_STEP_2[tab2][sample_rate_index];
361
+		sblimit = tab3 & 63;
362
+		tab3 >>= 6;
363
+	}
364
+
365
+	if (bound > sblimit) {
366
+		bound = sblimit;
367
+	}
368
+
369
+	// Read the allocation information
370
+	for (int sb = 0; sb < bound; sb++) {
371
+		self->allocation[0][sb] = read_allocation(self, sb, tab3);
372
+		self->allocation[1][sb] = read_allocation(self, sb, tab3);
373
+	}
374
+
375
+	for (int sb = bound; sb < sblimit; sb++) {
376
+		self->allocation[0][sb] = 
377
+			self->allocation[1][sb] =
378
+			read_allocation(self, sb, tab3);
379
+	}
380
+
381
+	// Read scale factor selector information
382
+	int channels = (mode == MODE_MONO) ? 1 : 2;
383
+	for (int sb = 0;  sb < sblimit; sb++) {
384
+		for (int ch = 0;  ch < channels; ch++) {
385
+			if (self->allocation[ch][sb]) {
386
+				self->scale_factor_info[ch][sb] = bit_buffer_read(self->bits, 2);
387
+			}
388
+		}
389
+		if (mode == MODE_MONO) {
390
+			self->scale_factor_info[1][sb] = self->scale_factor_info[0][sb];
391
+		}
392
+	}
393
+
394
+	// Read scale factors
395
+	for (int sb = 0;  sb < sblimit; sb++) {
396
+		for (int ch = 0;  ch < channels; ch++) {
397
+			if (self->allocation[ch][sb]) {
398
+				int *sf = self->scale_factor[ch][sb];
399
+				switch (self->scale_factor_info[ch][sb]) {
400
+					case 0:
401
+						sf[0] = bit_buffer_read(self->bits, 6);
402
+						sf[1] = bit_buffer_read(self->bits, 6);
403
+						sf[2] = bit_buffer_read(self->bits, 6);
404
+						break;
405
+					case 1:
406
+						sf[0] =
407
+						sf[1] = bit_buffer_read(self->bits, 6);
408
+						sf[2] = bit_buffer_read(self->bits, 6);
409
+						break;
410
+					case 2:
411
+						sf[0] =
412
+						sf[1] =
413
+						sf[2] = bit_buffer_read(self->bits, 6);
414
+						break;
415
+					case 3:
416
+						sf[0] = bit_buffer_read(self->bits, 6);
417
+						sf[1] =
418
+						sf[2] = bit_buffer_read(self->bits, 6);
419
+						break;
420
+				}
421
+			}
422
+		}
423
+		if (mode == MODE_MONO) {
424
+			self->scale_factor[1][sb][0] = self->scale_factor[0][sb][0];
425
+			self->scale_factor[1][sb][1] = self->scale_factor[0][sb][1];
426
+			self->scale_factor[1][sb][2] = self->scale_factor[0][sb][2];
427
+		}
428
+	}
429
+
430
+	// Coefficient input and reconstruction
431
+	int out_pos = 0;
432
+	for (int part = 0; part < 3; part++) {
433
+		for (int granule = 0; granule < 4; granule++) {
434
+
435
+			// Read the samples
436
+			for (int sb = 0; sb < bound; sb++) {
437
+				read_samples(self, 0, sb, part);
438
+				read_samples(self, 1, sb, part);
439
+			}
440
+			for (int sb = bound; sb < sblimit; sb++) {
441
+				read_samples(self, 0, sb, part);
442
+				self->sample[1][sb][0] = self->sample[0][sb][0];
443
+				self->sample[1][sb][1] = self->sample[0][sb][1];
444
+				self->sample[1][sb][2] = self->sample[0][sb][2];
445
+			}
446
+			for (int sb = sblimit; sb < 32; sb++) {
447
+				self->sample[0][sb][0] = 0;
448
+				self->sample[0][sb][1] = 0;
449
+				self->sample[0][sb][2] = 0;
450
+				self->sample[1][sb][0] = 0;
451
+				self->sample[1][sb][1] = 0;
452
+				self->sample[1][sb][2] = 0;
453
+			}
454
+
455
+			// Synthesis loop
456
+			for (int p = 0; p < 3; p++) {
457
+				// Shifting step
458
+				self->v_pos = (self->v_pos - 64) & 1023;
459
+
460
+				for (int ch = 0;  ch < 2; ch++) {
461
+					matrix_transform(self->sample[ch], p, self->V, self->v_pos);
462
+
463
+					// Build U, windowing, calculate output
464
+					memset(self->U, 0, sizeof(self->U));
465
+
466
+					int d_index = 512 - (self->v_pos >> 1);
467
+					int v_index = (self->v_pos % 128) >> 1;
468
+					while (v_index < 1024) {
469
+						for (int i = 0; i < 32; ++i) {
470
+							self->U[i] += self->D[d_index++] * self->V[v_index++];
471
+						}
472
+
473
+						v_index += 128-32;
474
+						d_index += 64-32;
475
+					}
476
+
477
+					v_index = (128-32 + 1024) - v_index;
478
+					d_index -= (512 - 32);
479
+					while (v_index < 1024) {
480
+						for (int i = 0; i < 32; ++i) {
481
+							self->U[i] += self->D[d_index++] * self->V[v_index++];
482
+						}
483
+
484
+						v_index += 128-32;
485
+						d_index += 64-32;
486
+					}
487
+
488
+					// Output samples
489
+					float *out_channel = ch == 0 
490
+						? self->channel_left 
491
+						: self->channel_right;
492
+					for (int j = 0; j < 32; j++) {
493
+						out_channel[out_pos + j] = (float)self->U[j] / 2147418112.0;
494
+					}
495
+				} // End of synthesis channel loop
496
+				out_pos += 32;
497
+			} // End of synthesis sub-block loop
498
+
499
+		} // Decoding of the granule finished
500
+	}
501
+
502
+	self->sample_rate = sample_rate;
503
+	return frame_size;
504
+}
505
+
506
+const quantizer_spec_t *read_allocation(mp2_decoder_t *self, int sb, int tab3) {
507
+	int tab4 = QUANT_LUT_STEP_3[tab3][sb];
508
+	int qtab = QUANT_LUT_STEP4[tab4 & 15][bit_buffer_read(self->bits, tab4 >> 4)];
509
+	return qtab ? (&QUANT_TAB[qtab - 1]) : 0;
510
+}
511
+
512
+void read_samples(mp2_decoder_t *self, int ch, int sb, int part) {
513
+	const quantizer_spec_t *q = self->allocation[ch][sb];
514
+	int sf = self->scale_factor[ch][sb][part];
515
+	int *sample = self->sample[ch][sb];
516
+	int val = 0;
517
+
518
+	if (!q) {
519
+		// No bits allocated for this subband
520
+		sample[0] = sample[1] = sample[2] = 0;
521
+		return;
522
+	}
523
+
524
+	// Resolve scalefactor
525
+	if (sf == 63) {
526
+		sf = 0;
527
+	}
528
+	else {
529
+		int shift = (sf / 3)|0;
530
+		sf = (SCALEFACTOR_BASE[sf % 3] + ((1 << shift) >> 1)) >> shift;
531
+	}
532
+
533
+	// Decode samples
534
+	int adj = q->levels;
535
+	if (q->group) {
536
+		// Decode grouped samples
537
+		val = bit_buffer_read(self->bits, q->bits);
538
+		sample[0] = val % adj;
539
+		val /= adj;
540
+		sample[1] = val % adj;
541
+		sample[2] = val / adj;
542
+	}
543
+	else {
544
+		// Decode direct samples
545
+		sample[0] = bit_buffer_read(self->bits, q->bits);
546
+		sample[1] = bit_buffer_read(self->bits, q->bits);
547
+		sample[2] = bit_buffer_read(self->bits, q->bits);
548
+	}
549
+
550
+	// Postmultiply samples
551
+	int scale = 65536 / (adj + 1);
552
+	adj = ((adj + 1) >> 1) - 1;
553
+
554
+	val = (adj - sample[0]) * scale;
555
+	sample[0] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12;
556
+
557
+	val = (adj - sample[1]) * scale;
558
+	sample[1] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12;
559
+
560
+	val = (adj - sample[2]) * scale;
561
+	sample[2] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12;
562
+}
563
+
564
+void matrix_transform(int s[32][3], int ss, float *d, int dp) {
565
+	float t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12,
566
+		t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24,
567
+		t25, t26, t27, t28, t29, t30, t31, t32, t33;
568
+
569
+	t01 = s[ 0][ss] + s[31][ss]; t02 = (float)(s[ 0][ss] - s[31][ss]) * 0.500602998235;
570
+	t03 = s[ 1][ss] + s[30][ss]; t04 = (float)(s[ 1][ss] - s[30][ss]) * 0.505470959898;
571
+	t05 = s[ 2][ss] + s[29][ss]; t06 = (float)(s[ 2][ss] - s[29][ss]) * 0.515447309923;
572
+	t07 = s[ 3][ss] + s[28][ss]; t08 = (float)(s[ 3][ss] - s[28][ss]) * 0.53104259109;
573
+	t09 = s[ 4][ss] + s[27][ss]; t10 = (float)(s[ 4][ss] - s[27][ss]) * 0.553103896034;
574
+	t11 = s[ 5][ss] + s[26][ss]; t12 = (float)(s[ 5][ss] - s[26][ss]) * 0.582934968206;
575
+	t13 = s[ 6][ss] + s[25][ss]; t14 = (float)(s[ 6][ss] - s[25][ss]) * 0.622504123036;
576
+	t15 = s[ 7][ss] + s[24][ss]; t16 = (float)(s[ 7][ss] - s[24][ss]) * 0.674808341455;
577
+	t17 = s[ 8][ss] + s[23][ss]; t18 = (float)(s[ 8][ss] - s[23][ss]) * 0.744536271002;
578
+	t19 = s[ 9][ss] + s[22][ss]; t20 = (float)(s[ 9][ss] - s[22][ss]) * 0.839349645416;
579
+	t21 = s[10][ss] + s[21][ss]; t22 = (float)(s[10][ss] - s[21][ss]) * 0.972568237862;
580
+	t23 = s[11][ss] + s[20][ss]; t24 = (float)(s[11][ss] - s[20][ss]) * 1.16943993343;
581
+	t25 = s[12][ss] + s[19][ss]; t26 = (float)(s[12][ss] - s[19][ss]) * 1.48416461631;
582
+	t27 = s[13][ss] + s[18][ss]; t28 = (float)(s[13][ss] - s[18][ss]) * 2.05778100995;
583
+	t29 = s[14][ss] + s[17][ss]; t30 = (float)(s[14][ss] - s[17][ss]) * 3.40760841847;
584
+	t31 = s[15][ss] + s[16][ss]; t32 = (float)(s[15][ss] - s[16][ss]) * 10.1900081235;
585
+
586
+	t33 = t01 + t31; t31 = (t01 - t31) * 0.502419286188;
587
+	t01 = t03 + t29; t29 = (t03 - t29) * 0.52249861494;
588
+	t03 = t05 + t27; t27 = (t05 - t27) * 0.566944034816;
589
+	t05 = t07 + t25; t25 = (t07 - t25) * 0.64682178336;
590
+	t07 = t09 + t23; t23 = (t09 - t23) * 0.788154623451;
591
+	t09 = t11 + t21; t21 = (t11 - t21) * 1.06067768599;
592
+	t11 = t13 + t19; t19 = (t13 - t19) * 1.72244709824;
593
+	t13 = t15 + t17; t17 = (t15 - t17) * 5.10114861869;
594
+	t15 = t33 + t13; t13 = (t33 - t13) * 0.509795579104;
595
+	t33 = t01 + t11; t01 = (t01 - t11) * 0.601344886935;
596
+	t11 = t03 + t09; t09 = (t03 - t09) * 0.899976223136;
597
+	t03 = t05 + t07; t07 = (t05 - t07) * 2.56291544774;
598
+	t05 = t15 + t03; t15 = (t15 - t03) * 0.541196100146;
599
+	t03 = t33 + t11; t11 = (t33 - t11) * 1.30656296488;
600
+	t33 = t05 + t03; t05 = (t05 - t03) * 0.707106781187;
601
+	t03 = t15 + t11; t15 = (t15 - t11) * 0.707106781187;
602
+	t03 += t15;
603
+	t11 = t13 + t07; t13 = (t13 - t07) * 0.541196100146;
604
+	t07 = t01 + t09; t09 = (t01 - t09) * 1.30656296488;
605
+	t01 = t11 + t07; t07 = (t11 - t07) * 0.707106781187;
606
+	t11 = t13 + t09; t13 = (t13 - t09) * 0.707106781187;
607
+	t11 += t13; t01 += t11; 
608
+	t11 += t07; t07 += t13;
609
+	t09 = t31 + t17; t31 = (t31 - t17) * 0.509795579104;
610
+	t17 = t29 + t19; t29 = (t29 - t19) * 0.601344886935;
611
+	t19 = t27 + t21; t21 = (t27 - t21) * 0.899976223136;
612
+	t27 = t25 + t23; t23 = (t25 - t23) * 2.56291544774;
613
+	t25 = t09 + t27; t09 = (t09 - t27) * 0.541196100146;
614
+	t27 = t17 + t19; t19 = (t17 - t19) * 1.30656296488;
615
+	t17 = t25 + t27; t27 = (t25 - t27) * 0.707106781187;
616
+	t25 = t09 + t19; t19 = (t09 - t19) * 0.707106781187;
617
+	t25 += t19;
618
+	t09 = t31 + t23; t31 = (t31 - t23) * 0.541196100146;
619
+	t23 = t29 + t21; t21 = (t29 - t21) * 1.30656296488;
620
+	t29 = t09 + t23; t23 = (t09 - t23) * 0.707106781187;
621
+	t09 = t31 + t21; t31 = (t31 - t21) * 0.707106781187;
622
+	t09 += t31;	t29 += t09;	t09 += t23;	t23 += t31;
623
+	t17 += t29;	t29 += t25;	t25 += t09;	t09 += t27;
624
+	t27 += t23;	t23 += t19; t19 += t31;	
625
+	t21 = t02 + t32; t02 = (t02 - t32) * 0.502419286188;
626
+	t32 = t04 + t30; t04 = (t04 - t30) * 0.52249861494;
627
+	t30 = t06 + t28; t28 = (t06 - t28) * 0.566944034816;
628
+	t06 = t08 + t26; t08 = (t08 - t26) * 0.64682178336;
629
+	t26 = t10 + t24; t10 = (t10 - t24) * 0.788154623451;
630
+	t24 = t12 + t22; t22 = (t12 - t22) * 1.06067768599;
631
+	t12 = t14 + t20; t20 = (t14 - t20) * 1.72244709824;
632
+	t14 = t16 + t18; t16 = (t16 - t18) * 5.10114861869;
633
+	t18 = t21 + t14; t14 = (t21 - t14) * 0.509795579104;
634
+	t21 = t32 + t12; t32 = (t32 - t12) * 0.601344886935;
635
+	t12 = t30 + t24; t24 = (t30 - t24) * 0.899976223136;
636
+	t30 = t06 + t26; t26 = (t06 - t26) * 2.56291544774;
637
+	t06 = t18 + t30; t18 = (t18 - t30) * 0.541196100146;
638
+	t30 = t21 + t12; t12 = (t21 - t12) * 1.30656296488;
639
+	t21 = t06 + t30; t30 = (t06 - t30) * 0.707106781187;
640
+	t06 = t18 + t12; t12 = (t18 - t12) * 0.707106781187;
641
+	t06 += t12;
642
+	t18 = t14 + t26; t26 = (t14 - t26) * 0.541196100146;
643
+	t14 = t32 + t24; t24 = (t32 - t24) * 1.30656296488;
644
+	t32 = t18 + t14; t14 = (t18 - t14) * 0.707106781187;
645
+	t18 = t26 + t24; t24 = (t26 - t24) * 0.707106781187;
646
+	t18 += t24; t32 += t18; 
647
+	t18 += t14; t26 = t14 + t24;
648
+	t14 = t02 + t16; t02 = (t02 - t16) * 0.509795579104;
649
+	t16 = t04 + t20; t04 = (t04 - t20) * 0.601344886935;
650
+	t20 = t28 + t22; t22 = (t28 - t22) * 0.899976223136;
651
+	t28 = t08 + t10; t10 = (t08 - t10) * 2.56291544774;
652
+	t08 = t14 + t28; t14 = (t14 - t28) * 0.541196100146;
653
+	t28 = t16 + t20; t20 = (t16 - t20) * 1.30656296488;
654
+	t16 = t08 + t28; t28 = (t08 - t28) * 0.707106781187;
655
+	t08 = t14 + t20; t20 = (t14 - t20) * 0.707106781187;
656
+	t08 += t20;
657
+	t14 = t02 + t10; t02 = (t02 - t10) * 0.541196100146;
658
+	t10 = t04 + t22; t22 = (t04 - t22) * 1.30656296488;
659
+	t04 = t14 + t10; t10 = (t14 - t10) * 0.707106781187;
660
+	t14 = t02 + t22; t02 = (t02 - t22) * 0.707106781187;
661
+	t14 += t02;	t04 += t14;	t14 += t10;	t10 += t02;
662
+	t16 += t04;	t04 += t08;	t08 += t14;	t14 += t28;
663
+	t28 += t10;	t10 += t20;	t20 += t02;	t21 += t16;
664
+	t16 += t32;	t32 += t04;	t04 += t06;	t06 += t08;
665
+	t08 += t18;	t18 += t14;	t14 += t30;	t30 += t28;
666
+	t28 += t26;	t26 += t10;	t10 += t12;	t12 += t20;
667
+	t20 += t24;	t24 += t02;
668
+
669
+	d[dp + 48] = -t33;
670
+	d[dp + 49] = d[dp + 47] = -t21;
671
+	d[dp + 50] = d[dp + 46] = -t17;
672
+	d[dp + 51] = d[dp + 45] = -t16;
673
+	d[dp + 52] = d[dp + 44] = -t01;
674
+	d[dp + 53] = d[dp + 43] = -t32;
675
+	d[dp + 54] = d[dp + 42] = -t29;
676
+	d[dp + 55] = d[dp + 41] = -t04;
677
+	d[dp + 56] = d[dp + 40] = -t03;
678
+	d[dp + 57] = d[dp + 39] = -t06;
679
+	d[dp + 58] = d[dp + 38] = -t25;
680
+	d[dp + 59] = d[dp + 37] = -t08;
681
+	d[dp + 60] = d[dp + 36] = -t11;
682
+	d[dp + 61] = d[dp + 35] = -t18;
683
+	d[dp + 62] = d[dp + 34] = -t09;
684
+	d[dp + 63] = d[dp + 33] = -t14;
685
+	d[dp + 32] = -t05;
686
+	d[dp +  0] = t05; d[dp + 31] = -t30;
687
+	d[dp +  1] = t30; d[dp + 30] = -t27;
688
+	d[dp +  2] = t27; d[dp + 29] = -t28;
689
+	d[dp +  3] = t28; d[dp + 28] = -t07;
690
+	d[dp +  4] = t07; d[dp + 27] = -t26;
691
+	d[dp +  5] = t26; d[dp + 26] = -t23;
692
+	d[dp +  6] = t23; d[dp + 25] = -t10;
693
+	d[dp +  7] = t10; d[dp + 24] = -t15;
694
+	d[dp +  8] = t15; d[dp + 23] = -t12;
695
+	d[dp +  9] = t12; d[dp + 22] = -t19;
696
+	d[dp + 10] = t19; d[dp + 21] = -t20;
697
+	d[dp + 11] = t20; d[dp + 20] = -t13;
698
+	d[dp + 12] = t13; d[dp + 19] = -t24;
699
+	d[dp + 13] = t24; d[dp + 18] = -t31;
700
+	d[dp + 14] = t31; d[dp + 17] = -t02;
701
+	d[dp + 15] = t02; d[dp + 16] =  0.0;
702
+};
703
+

+ 22 - 0
src/wasm/mp2.h Näytä tiedosto

@@ -0,0 +1,22 @@
1
+#ifndef MP2_H
2
+#define MP2_H
3
+
4
+#include <stdbool.h>
5
+#include <stdint.h>
6
+#include "buffer.h"
7
+
8
+typedef struct mp2_decoder_t mp2_decoder_t;
9
+
10
+mp2_decoder_t *mp2_decoder_create(unsigned int buffer_size, bit_buffer_mode_t buffer_mode);
11
+void mp2_decoder_destroy(mp2_decoder_t *self);
12
+void *mp2_decoder_get_write_ptr(mp2_decoder_t *self, unsigned int byte_size);
13
+int mp2_decoder_get_index(mp2_decoder_t *self);
14
+void mp2_decoder_set_index(mp2_decoder_t *self, unsigned int index);
15
+void mp2_decoder_did_write(mp2_decoder_t *self, unsigned int byte_size);
16
+
17
+void *mp2_decoder_get_left_channel_ptr(mp2_decoder_t *self);
18
+void *mp2_decoder_get_right_channel_ptr(mp2_decoder_t *self);
19
+int mp2_decoder_get_sample_rate(mp2_decoder_t *self);
20
+int mp2_decoder_decode(mp2_decoder_t *self);
21
+
22
+#endif

File diff suppressed because it is too large
+ 1746 - 0
src/wasm/mpeg1.c


+ 27 - 0
src/wasm/mpeg1.h Näytä tiedosto

@@ -0,0 +1,27 @@
1
+#ifndef MPEG1_H
2
+#define MPEG1_H
3
+
4
+#include <stdbool.h>
5
+#include <stdint.h>
6
+#include "buffer.h"
7
+
8
+typedef struct mpeg1_decoder_t mpeg1_decoder_t;
9
+
10
+mpeg1_decoder_t *mpeg1_decoder_create(unsigned int buffer_size, bit_buffer_mode_t buffer_mode);
11
+void mpeg1_decoder_destroy(mpeg1_decoder_t *self);
12
+void *mpeg1_decoder_get_write_ptr(mpeg1_decoder_t *self, unsigned int byte_size);
13
+int mpeg1_decoder_get_index(mpeg1_decoder_t *self);
14
+void mpeg1_decoder_set_index(mpeg1_decoder_t *self, unsigned int index);
15
+void mpeg1_decoder_did_write(mpeg1_decoder_t *self, unsigned int byte_size);
16
+
17
+int mpeg1_decoder_has_sequence_header(mpeg1_decoder_t *self);
18
+float mpeg1_decoder_get_frame_rate(mpeg1_decoder_t *self);
19
+int mpeg1_decoder_get_coded_size(mpeg1_decoder_t *self);
20
+int mpeg1_decoder_get_width(mpeg1_decoder_t *self);
21
+int mpeg1_decoder_get_height(mpeg1_decoder_t *self);
22
+void *mpeg1_decoder_get_y_ptr(mpeg1_decoder_t *self);
23
+void *mpeg1_decoder_get_cr_ptr(mpeg1_decoder_t *self);
24
+void *mpeg1_decoder_get_cb_ptr(mpeg1_decoder_t *self);
25
+bool mpeg1_decoder_decode(mpeg1_decoder_t *self);
26
+
27
+#endif