Skip to content

Commit 128be61

Browse files
Replace external brotli.js with WASM
Removes brotli.js and polyfills used to decode .br files. Instead, use existing libbrotlidec on C++ code, using adapted source from https://github.com/google/brotli/blob/7f740f1308336e9ec0afdb9434896307859f5dc9/go/cbrotli/reader.go (which we depend on). This saves about 100 KiB or so, mostly extra dictionary size.
1 parent 741d418 commit 128be61

File tree

9 files changed

+141
-21
lines changed

9 files changed

+141
-21
lines changed

Makefile

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ $(DIST_DIR)/lib/libexpat.a: build/lib/expat/configured
4747
$(JSO_MAKE) install
4848

4949
# Brotli
50-
build/lib/brotli/js/decode.js: build/lib/brotli/configured
51-
build/lib/brotli/js/polyfill.js: build/lib/brotli/configured
5250
build/lib/brotli/configured: lib/brotli $(wildcard $(BASE_DIR)build/patches/brotli/*.patch)
5351
$(call PREPARE_SRC_PATCHED,brotli)
5452
touch build/lib/brotli/configured
@@ -155,7 +153,7 @@ all-src:
155153
EMCC_COMMON_ARGS = \
156154
$(LDFLAGS) \
157155
-s AUTO_NATIVE_LIBRARIES=0 \
158-
-s EXPORTED_FUNCTIONS="['_main', '_malloc']" \
156+
-s EXPORTED_FUNCTIONS="['_main', '_malloc', '_free']" \
159157
-s EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap', 'getValue', 'FS_createPreloadedFile', 'FS_createPath']" \
160158
--use-preload-plugins \
161159
--preload-file assets/default.woff2 \
@@ -167,23 +165,20 @@ EMCC_COMMON_ARGS = \
167165

168166
dist: src/subtitles-octopus-worker.bc dist/js/subtitles-octopus-worker.js dist/js/subtitles-octopus-worker-legacy.js dist/js/subtitles-octopus.js dist/js/COPYRIGHT
169167

170-
dist/js/subtitles-octopus-worker.js: src/subtitles-octopus-worker.bc src/pre-worker.js src/SubOctpInterface.js src/post-worker.js build/lib/brotli/js/decode.js
168+
dist/js/subtitles-octopus-worker.js: src/subtitles-octopus-worker.bc src/pre-worker.js src/SubOctpInterface.js src/post-worker.js
171169
mkdir -p dist/js
172170
emcc src/subtitles-octopus-worker.bc $(OCTP_DEPS) \
173171
--pre-js src/pre-worker.js \
174-
--pre-js build/lib/brotli/js/decode.js \
175172
--post-js src/SubOctpInterface.js \
176173
--post-js src/post-worker.js \
177174
-s WASM=1 \
178175
$(EMCC_COMMON_ARGS)
179176

180-
dist/js/subtitles-octopus-worker-legacy.js: src/subtitles-octopus-worker.bc src/polyfill.js src/pre-worker.js src/SubOctpInterface.js src/post-worker.js build/lib/brotli/js/decode.js build/lib/brotli/js/polyfill.js
177+
dist/js/subtitles-octopus-worker-legacy.js: src/subtitles-octopus-worker.bc src/polyfill.js src/pre-worker.js src/SubOctpInterface.js src/post-worker.js
181178
mkdir -p dist/js
182179
emcc src/subtitles-octopus-worker.bc $(OCTP_DEPS) \
183180
--pre-js src/polyfill.js \
184-
--pre-js build/lib/brotli/js/polyfill.js \
185181
--pre-js src/pre-worker.js \
186-
--pre-js build/lib/brotli/js/decode.js \
187182
--post-js src/SubOctpInterface.js \
188183
--post-js src/post-worker.js \
189184
-s WASM=0 \

build/patches/brotli/0001-fix-brotli-js-for-webworkers.patch

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
CXX = em++ -c
44
CXXFLAGS = -O3 -g4
55
LIBASS_CXXFLAGS = $(shell pkg-config --static --cflags "libass >= 0.14.0")
6-
LOCAL_CXXFLAGS = -Wall -Wno-deprecated $(LIBASS_CXXFLAGS)
6+
BROTLI_CXXFLAGS = $(shell pkg-config --static --cflags "libbrotlidec")
7+
LOCAL_CXXFLAGS = -Wall -Wno-deprecated $(LIBASS_CXXFLAGS) $(BROTLI_CXXFLAGS)
78

89
all: subtitles-octopus-worker.bc
910

src/SubtitleOctopus.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "../lib/libass/libass/ass.h"
1111

1212
#include "libass.cpp"
13+
#include "brotli.cpp"
1314

1415
#ifdef __EMSCRIPTEN__
1516
#include <emscripten.h>

src/SubtitleOctopus.idl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ interface RenderBlendResult {
165165
attribute ByteString image;
166166
};
167167

168+
[NoDelete]
169+
interface Brotli {
170+
void Brotli();
171+
ByteString decode([Const] ByteString encoded, unsigned long encoded_size, IntPtr decoded_size);
172+
};
173+
168174
interface SubtitleOctopus {
169175
void SubtitleOctopus();
170176
attribute ASS_Track track;

src/brotli.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Adjusted from go cbrotli reader https://github.com/google/brotli/blob/7f740f1308336e9ec0afdb9434896307859f5dc9/go/cbrotli/reader.go
2+
//
3+
// Copyright 2016 Google Inc. All Rights Reserved.
4+
//
5+
// Distributed under MIT license.
6+
// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
7+
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
#include <stdarg.h>
11+
#include <string.h>
12+
#include <vector>
13+
#include <cstdint>
14+
15+
#include <brotli/decode.h>
16+
17+
static BrotliDecoderResult DecompressStream(BrotliDecoderState* s,
18+
uint8_t* out, size_t out_len,
19+
const uint8_t* in, size_t in_len,
20+
size_t* bytes_written,
21+
size_t* bytes_consumed) {
22+
size_t in_remaining = in_len;
23+
size_t out_remaining = out_len;
24+
BrotliDecoderResult result = BrotliDecoderDecompressStream(
25+
s, &in_remaining, &in, &out_remaining, &out, NULL);
26+
*bytes_written = out_len - out_remaining;
27+
*bytes_consumed = in_len - in_remaining;
28+
return result;
29+
}
30+
31+
#define BUF_SIZE 1024 * 64
32+
33+
class Brotli {
34+
public:
35+
36+
static uint8_t* decode(const uint8_t* encoded, int encoded_size, int* decoded_size) {
37+
*decoded_size = 0;
38+
39+
BrotliDecoderState* state = BrotliDecoderCreateInstance(NULL, NULL, NULL);
40+
if (state == NULL){
41+
return NULL;
42+
}
43+
44+
size_t written, consumed;
45+
46+
const uint8_t* in = encoded;
47+
size_t in_size = encoded_size;
48+
49+
std::vector<uint8_t> result_buf;
50+
uint8_t* out_buf = (uint8_t*)malloc(BUF_SIZE);
51+
if(out_buf == NULL){
52+
BrotliDecoderDestroyInstance(state);
53+
return NULL;
54+
}
55+
56+
while(in_size > 0){
57+
BrotliDecoderResult result = DecompressStream(state, out_buf, BUF_SIZE, in, in_size, &written, &consumed);
58+
59+
in += consumed;
60+
in_size -= consumed;
61+
62+
63+
if(written > 0){
64+
result_buf.insert(result_buf.end(), out_buf, out_buf + written);
65+
}
66+
67+
switch(result){
68+
case BROTLI_DECODER_RESULT_SUCCESS:
69+
break;
70+
case BROTLI_DECODER_RESULT_ERROR:
71+
free(out_buf);
72+
BrotliDecoderDestroyInstance(state);
73+
return NULL;
74+
case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT:
75+
if(written == 0){
76+
free(out_buf);
77+
BrotliDecoderDestroyInstance(state);
78+
return NULL;
79+
}
80+
break;
81+
case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT:
82+
break;
83+
}
84+
}
85+
86+
free(out_buf);
87+
BrotliDecoderDestroyInstance(state);
88+
89+
uint8_t* decoded = (uint8_t*)malloc(result_buf.size());
90+
std::copy(result_buf.begin(), result_buf.end(), decoded);
91+
*decoded_size = result_buf.size();
92+
return decoded;
93+
}
94+
95+
};

src/post-worker.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,46 @@ self.freeTrack = function () {
103103
self.getRenderMethod()();
104104
};
105105

106+
self.decodeBrotliArray = function (uint8array) {
107+
//Allocate and copy brotli encoded input into the heap, using buf ptr as offset
108+
var buf = Module._malloc(uint8array.length);
109+
Module["HEAPU8"].set(uint8array, buf);
110+
111+
//Allocate return length memory
112+
var decode_length_ptr = Module._malloc(4);
113+
114+
var br = new Module.Brotli();
115+
116+
//uint8_t* decoded;
117+
var decoded = br.decode(buf, uint8array.length, decode_length_ptr);
118+
119+
//int decode_length = *decode_length_ptr
120+
var decode_length = Module.getValue(decode_length_ptr, "i32");
121+
122+
//free input buffer and return length memory
123+
Module._free(buf);
124+
Module._free(decode_length_ptr);
125+
126+
if(decoded === 0){
127+
//decode err
128+
throw "could not decode brotli file";
129+
}
130+
131+
//copy data from the decoded ptr in the heap to a slice, then copy it
132+
var content = new Uint8Array(new Uint8Array(Module["HEAPU8"].buffer, decoded, decode_length));
133+
134+
Module._free(decoded);
135+
return content;
136+
}
137+
106138
/**
107139
* Set the subtitle track.
108140
* @param {!string} url the URL of the subtitle file.
109141
*/
110142
self.setTrackByUrl = function (url) {
111143
var content = "";
112144
if (isBrotliFile(url)) {
113-
content = Module["BrotliDecode"](readBinary(url))
145+
content = self.decodeBrotliArray(readBinary(url));
114146
} else {
115147
content = read_(url);
116148
}

src/pre-worker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Module["preRun"].push(function () {
6161
if (!self.subContent) {
6262
// We can use sync xhr cause we're inside Web Worker
6363
if (isBrotliFile(self.subUrl)) {
64-
self.subContent = Module["BrotliDecode"](readBinary(self.subUrl))
64+
self.subContent = self.decodeBrotliArray(readBinary(self.subUrl));
6565
} else {
6666
self.subContent = read_(self.subUrl);
6767
}

0 commit comments

Comments
 (0)