@cloudflare/realtimekit-virtual-background 0.0.1 → 0.0.2-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +149 -0
- package/dist/index.cjs.js +231 -0
- package/dist/index.es.js +4266 -0
- package/dist/index.iife.js +231 -0
- package/favicon.svg +15 -0
- package/package.json +25 -5
- package/types/ImageBackgroundTransformer.d.ts +9 -0
- package/types/SimpleBackgroundTransformer.d.ts +9 -0
- package/types/client/RealtimeKitVideoBackgroundTransformer.d.ts +49 -0
- package/types/common/BackgroundTransformer.d.ts +10 -0
- package/types/core/helpers/backgroundHelper.d.ts +6 -0
- package/types/core/helpers/postProcessingHelper.d.ts +12 -0
- package/types/core/helpers/renderingPipelineHelper.d.ts +6 -0
- package/types/core/helpers/segmentationHelper.d.ts +16 -0
- package/types/core/helpers/sourceHelper.d.ts +11 -0
- package/types/core/hooks/useTFLite.d.ts +21 -0
- package/types/index.d.ts +2 -0
- package/types/pipelines/canvas2d/canvas2dPipeline.d.ts +11 -0
- package/types/pipelines/helpers/webglHelper.d.ts +18 -0
- package/types/pipelines/webgl2/backgroundBlurStage.d.ts +7 -0
- package/types/pipelines/webgl2/backgroundImageStage.d.ts +10 -0
- package/types/pipelines/webgl2/jointBilateralFilterStage.d.ts +7 -0
- package/types/pipelines/webgl2/loadSegmentationStage.d.ts +6 -0
- package/types/pipelines/webgl2/resizingStage.d.ts +7 -0
- package/types/pipelines/webgl2/softmaxStage.d.ts +6 -0
- package/types/pipelines/webgl2/webgl2Pipeline.d.ts +11 -0
- package/types/tflite/tflite-simd.d.ts +2 -0
- package/types/tflite/tflite.d.ts +2 -0
- package/types/utils/browser.d.ts +3 -0
- package/types/utils/image.d.ts +2 -0
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,4266 @@
|
|
|
1
|
+
var __accessCheck = (obj, member, msg) => {
|
|
2
|
+
if (!member.has(obj))
|
|
3
|
+
throw TypeError("Cannot " + msg);
|
|
4
|
+
};
|
|
5
|
+
var __privateGet = (obj, member, getter) => {
|
|
6
|
+
__accessCheck(obj, member, "read from private field");
|
|
7
|
+
return getter ? getter.call(obj) : member.get(obj);
|
|
8
|
+
};
|
|
9
|
+
var __privateAdd = (obj, member, value) => {
|
|
10
|
+
if (member.has(obj))
|
|
11
|
+
throw TypeError("Cannot add the same private member more than once");
|
|
12
|
+
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
13
|
+
};
|
|
14
|
+
var __privateSet = (obj, member, value, setter) => {
|
|
15
|
+
__accessCheck(obj, member, "write to private field");
|
|
16
|
+
setter ? setter.call(obj, value) : member.set(obj, value);
|
|
17
|
+
return value;
|
|
18
|
+
};
|
|
19
|
+
var _initParams, _activeRunId, _initParams2, _activeRunId2, _imageBackgroundTransformer, _simpleBackgroundTrasnformer;
|
|
20
|
+
class BackgroundTransformer {
|
|
21
|
+
constructor() {
|
|
22
|
+
this.createCameraVideoElement = async (rawVideoTrack) => {
|
|
23
|
+
const cameraTrack = rawVideoTrack;
|
|
24
|
+
const { height, width } = cameraTrack.getSettings();
|
|
25
|
+
if (height === void 0 || width === void 0) {
|
|
26
|
+
throw Error("Background removal can't commence as Height and Width of the video feed is undefined");
|
|
27
|
+
}
|
|
28
|
+
const cameraVideoElement = document.createElement("video");
|
|
29
|
+
cameraVideoElement.width = width;
|
|
30
|
+
cameraVideoElement.height = height;
|
|
31
|
+
cameraVideoElement.srcObject = new MediaStream([cameraTrack]);
|
|
32
|
+
cameraVideoElement.autoplay = true;
|
|
33
|
+
cameraVideoElement.muted = true;
|
|
34
|
+
cameraVideoElement.playsInline = true;
|
|
35
|
+
cameraVideoElement.controls = true;
|
|
36
|
+
try {
|
|
37
|
+
await cameraVideoElement.play();
|
|
38
|
+
} catch (ex) {
|
|
39
|
+
console.warn("RealtimeKitVideoBackgroundTransformer:: Couldn't play raw video feed in detached mode");
|
|
40
|
+
}
|
|
41
|
+
return cameraVideoElement;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const loadImage = (src) => new Promise((resolve, reject) => {
|
|
46
|
+
const img = new Image();
|
|
47
|
+
img.onload = () => resolve(img);
|
|
48
|
+
img.onerror = reject;
|
|
49
|
+
img.src = src;
|
|
50
|
+
img.crossOrigin = "anonymous";
|
|
51
|
+
});
|
|
52
|
+
const createImageFromVideoElement = (video) => new Promise((resolve, reject) => {
|
|
53
|
+
const canvas = document.createElement("canvas");
|
|
54
|
+
const ctx = canvas.getContext("2d");
|
|
55
|
+
canvas.width = video.videoWidth;
|
|
56
|
+
canvas.height = video.videoHeight;
|
|
57
|
+
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
58
|
+
const img = new Image();
|
|
59
|
+
img.onload = () => resolve(img);
|
|
60
|
+
img.onerror = reject;
|
|
61
|
+
img.src = canvas.toDataURL("image/jpeg");
|
|
62
|
+
img.crossOrigin = "anonymous";
|
|
63
|
+
});
|
|
64
|
+
const inputResolutions = {
|
|
65
|
+
"640x360": [640, 360],
|
|
66
|
+
"256x256": [256, 256],
|
|
67
|
+
"256x144": [256, 144],
|
|
68
|
+
"160x96": [160, 96]
|
|
69
|
+
};
|
|
70
|
+
function getTFLiteModelFileName(model, inputResolution) {
|
|
71
|
+
switch (model) {
|
|
72
|
+
case "meet":
|
|
73
|
+
return inputResolution === "256x144" ? "segm_full_v679" : "segm_lite_v681";
|
|
74
|
+
case "mlkit":
|
|
75
|
+
return "selfiesegmentation_mlkit-256x256-2021_01_19-v1215.f16";
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(`No TFLite file for this segmentation model: ${model}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const glsl = String.raw;
|
|
81
|
+
function createPiplelineStageProgram(gl, vertexShader, fragmentShader, positionBuffer, texCoordBuffer) {
|
|
82
|
+
const program = createProgram(gl, vertexShader, fragmentShader);
|
|
83
|
+
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
|
|
84
|
+
gl.enableVertexAttribArray(positionAttributeLocation);
|
|
85
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
86
|
+
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
|
|
87
|
+
const texCoordAttributeLocation = gl.getAttribLocation(program, "a_texCoord");
|
|
88
|
+
gl.enableVertexAttribArray(texCoordAttributeLocation);
|
|
89
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
|
90
|
+
gl.vertexAttribPointer(texCoordAttributeLocation, 2, gl.FLOAT, false, 0, 0);
|
|
91
|
+
return program;
|
|
92
|
+
}
|
|
93
|
+
function createProgram(gl, vertexShader, fragmentShader) {
|
|
94
|
+
const program = gl.createProgram();
|
|
95
|
+
gl.attachShader(program, vertexShader);
|
|
96
|
+
gl.attachShader(program, fragmentShader);
|
|
97
|
+
gl.linkProgram(program);
|
|
98
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Could not link WebGL program: ${gl.getProgramInfoLog(program)}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return program;
|
|
104
|
+
}
|
|
105
|
+
function compileShader(gl, shaderType, shaderSource) {
|
|
106
|
+
const shader = gl.createShader(shaderType);
|
|
107
|
+
gl.shaderSource(shader, shaderSource);
|
|
108
|
+
gl.compileShader(shader);
|
|
109
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
110
|
+
throw new Error(`Could not compile shader: ${gl.getShaderInfoLog(shader)}`);
|
|
111
|
+
}
|
|
112
|
+
return shader;
|
|
113
|
+
}
|
|
114
|
+
function createTexture(gl, internalformat, width, height, minFilter = gl.NEAREST, magFilter = gl.NEAREST) {
|
|
115
|
+
const texture = gl.createTexture();
|
|
116
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
117
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
118
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
119
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
|
|
120
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);
|
|
121
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, internalformat, width, height);
|
|
122
|
+
return texture;
|
|
123
|
+
}
|
|
124
|
+
async function readPixelsAsync(timerWorker, gl, x, y, width, height, format, type, dest) {
|
|
125
|
+
const buf = gl.createBuffer();
|
|
126
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buf);
|
|
127
|
+
gl.bufferData(gl.PIXEL_PACK_BUFFER, dest.byteLength, gl.STREAM_READ);
|
|
128
|
+
gl.readPixels(x, y, width, height, format, type, 0);
|
|
129
|
+
gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
|
|
130
|
+
await getBufferSubDataAsync(
|
|
131
|
+
timerWorker,
|
|
132
|
+
gl,
|
|
133
|
+
gl.PIXEL_PACK_BUFFER,
|
|
134
|
+
buf,
|
|
135
|
+
0,
|
|
136
|
+
dest
|
|
137
|
+
);
|
|
138
|
+
gl.deleteBuffer(buf);
|
|
139
|
+
return dest;
|
|
140
|
+
}
|
|
141
|
+
async function getBufferSubDataAsync(timerWorker, gl, target, buffer, srcByteOffset, dstBuffer, dstOffset, length) {
|
|
142
|
+
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
143
|
+
gl.flush();
|
|
144
|
+
const res = await clientWaitAsync(timerWorker, gl, sync);
|
|
145
|
+
gl.deleteSync(sync);
|
|
146
|
+
if (res !== gl.WAIT_FAILED) {
|
|
147
|
+
gl.bindBuffer(target, buffer);
|
|
148
|
+
gl.getBufferSubData(target, srcByteOffset, dstBuffer, dstOffset, length);
|
|
149
|
+
gl.bindBuffer(target, null);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function clientWaitAsync(timerWorker, gl, sync) {
|
|
153
|
+
return new Promise((resolve) => {
|
|
154
|
+
function test() {
|
|
155
|
+
const res = gl.clientWaitSync(sync, 0, 0);
|
|
156
|
+
if (res === gl.WAIT_FAILED) {
|
|
157
|
+
resolve(res);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (res === gl.TIMEOUT_EXPIRED) {
|
|
161
|
+
timerWorker.setTimeout(test, 0);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
resolve(res);
|
|
165
|
+
}
|
|
166
|
+
timerWorker.setTimeout(test, 0);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function buildBackgroundBlurStage(gl, vertexShader, positionBuffer, texCoordBuffer, personMaskTexture, canvas, backgroundConfig) {
|
|
170
|
+
const blurPass = buildBlurPass(
|
|
171
|
+
gl,
|
|
172
|
+
vertexShader,
|
|
173
|
+
positionBuffer,
|
|
174
|
+
texCoordBuffer,
|
|
175
|
+
personMaskTexture,
|
|
176
|
+
canvas,
|
|
177
|
+
backgroundConfig
|
|
178
|
+
);
|
|
179
|
+
const blendPass = buildBlendPass(gl, positionBuffer, texCoordBuffer, canvas);
|
|
180
|
+
function render() {
|
|
181
|
+
blurPass.render();
|
|
182
|
+
blendPass.render();
|
|
183
|
+
}
|
|
184
|
+
function updateCoverage(coverage) {
|
|
185
|
+
blendPass.updateCoverage(coverage);
|
|
186
|
+
}
|
|
187
|
+
function cleanUp() {
|
|
188
|
+
blendPass.cleanUp();
|
|
189
|
+
blurPass.cleanUp();
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
render,
|
|
193
|
+
updateCoverage,
|
|
194
|
+
cleanUp
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function buildBlurPass(gl, vertexShader, positionBuffer, texCoordBuffer, personMaskTexture, canvas, backgroundConfig) {
|
|
198
|
+
const fragmentShaderSource = glsl`#version 300 es
|
|
199
|
+
|
|
200
|
+
precision highp float;
|
|
201
|
+
|
|
202
|
+
uniform sampler2D u_inputFrame;
|
|
203
|
+
uniform sampler2D u_personMask;
|
|
204
|
+
uniform vec2 u_texelSize;
|
|
205
|
+
uniform float u_blurAmount;
|
|
206
|
+
|
|
207
|
+
in vec2 v_texCoord;
|
|
208
|
+
|
|
209
|
+
out vec4 outColor;
|
|
210
|
+
|
|
211
|
+
const float offset[5] = float[](0.0, 1.0, 2.0, 3.0, 4.0);
|
|
212
|
+
const float weight[5] = float[](0.2270270270, 0.1945945946, 0.1216216216,
|
|
213
|
+
0.0540540541, 0.0162162162);
|
|
214
|
+
|
|
215
|
+
void main() {
|
|
216
|
+
vec4 centerColor = texture(u_inputFrame, v_texCoord);
|
|
217
|
+
float personMask = texture(u_personMask, v_texCoord).a;
|
|
218
|
+
|
|
219
|
+
vec4 frameColor = centerColor * weight[0] * (1.0 - personMask);
|
|
220
|
+
|
|
221
|
+
for (int i = 1; i < 5; i++) {
|
|
222
|
+
vec2 offset = vec2(offset[i]) * u_texelSize * u_blurAmount;
|
|
223
|
+
|
|
224
|
+
vec2 texCoord = v_texCoord + offset;
|
|
225
|
+
frameColor += texture(u_inputFrame, texCoord) * weight[i] *
|
|
226
|
+
(1.0 - texture(u_personMask, texCoord).a);
|
|
227
|
+
|
|
228
|
+
texCoord = v_texCoord - offset;
|
|
229
|
+
frameColor += texture(u_inputFrame, texCoord) * weight[i] *
|
|
230
|
+
(1.0 - texture(u_personMask, texCoord).a);
|
|
231
|
+
}
|
|
232
|
+
outColor = vec4(frameColor.rgb + (1.0 - frameColor.a) * centerColor.rgb, 1.0);
|
|
233
|
+
}
|
|
234
|
+
`;
|
|
235
|
+
const scale = 0.5;
|
|
236
|
+
const outputWidth = canvas.width * scale;
|
|
237
|
+
const outputHeight = canvas.height * scale;
|
|
238
|
+
const texelWidth = 1 / outputWidth;
|
|
239
|
+
const texelHeight = 1 / outputHeight;
|
|
240
|
+
const fragmentShader = compileShader(
|
|
241
|
+
gl,
|
|
242
|
+
gl.FRAGMENT_SHADER,
|
|
243
|
+
fragmentShaderSource
|
|
244
|
+
);
|
|
245
|
+
const program = createPiplelineStageProgram(
|
|
246
|
+
gl,
|
|
247
|
+
vertexShader,
|
|
248
|
+
fragmentShader,
|
|
249
|
+
positionBuffer,
|
|
250
|
+
texCoordBuffer
|
|
251
|
+
);
|
|
252
|
+
const inputFrameLocation = gl.getUniformLocation(program, "u_inputFrame");
|
|
253
|
+
const personMaskLocation = gl.getUniformLocation(program, "u_personMask");
|
|
254
|
+
const texelSizeLocation = gl.getUniformLocation(program, "u_texelSize");
|
|
255
|
+
const blurAmountLocation = gl.getUniformLocation(program, "u_blurAmount");
|
|
256
|
+
const texture1 = createTexture(
|
|
257
|
+
gl,
|
|
258
|
+
gl.RGBA8,
|
|
259
|
+
outputWidth,
|
|
260
|
+
outputHeight,
|
|
261
|
+
gl.NEAREST,
|
|
262
|
+
gl.LINEAR
|
|
263
|
+
);
|
|
264
|
+
const texture2 = createTexture(
|
|
265
|
+
gl,
|
|
266
|
+
gl.RGBA8,
|
|
267
|
+
outputWidth,
|
|
268
|
+
outputHeight,
|
|
269
|
+
gl.NEAREST,
|
|
270
|
+
gl.LINEAR
|
|
271
|
+
);
|
|
272
|
+
const frameBuffer1 = gl.createFramebuffer();
|
|
273
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer1);
|
|
274
|
+
gl.framebufferTexture2D(
|
|
275
|
+
gl.FRAMEBUFFER,
|
|
276
|
+
gl.COLOR_ATTACHMENT0,
|
|
277
|
+
gl.TEXTURE_2D,
|
|
278
|
+
texture1,
|
|
279
|
+
0
|
|
280
|
+
);
|
|
281
|
+
const frameBuffer2 = gl.createFramebuffer();
|
|
282
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer2);
|
|
283
|
+
gl.framebufferTexture2D(
|
|
284
|
+
gl.FRAMEBUFFER,
|
|
285
|
+
gl.COLOR_ATTACHMENT0,
|
|
286
|
+
gl.TEXTURE_2D,
|
|
287
|
+
texture2,
|
|
288
|
+
0
|
|
289
|
+
);
|
|
290
|
+
gl.useProgram(program);
|
|
291
|
+
const desiredBlurAmount = Math.max(0, Math.min(backgroundConfig.blurLength / 10, 10));
|
|
292
|
+
gl.uniform1f(blurAmountLocation, desiredBlurAmount);
|
|
293
|
+
gl.uniform1i(personMaskLocation, 1);
|
|
294
|
+
function render() {
|
|
295
|
+
gl.viewport(0, 0, outputWidth, outputHeight);
|
|
296
|
+
gl.useProgram(program);
|
|
297
|
+
gl.uniform1i(inputFrameLocation, 0);
|
|
298
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
299
|
+
gl.bindTexture(gl.TEXTURE_2D, personMaskTexture);
|
|
300
|
+
for (let i = 0; i < 3; i++) {
|
|
301
|
+
gl.uniform2f(texelSizeLocation, 0, texelHeight);
|
|
302
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer1);
|
|
303
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
304
|
+
gl.activeTexture(gl.TEXTURE2);
|
|
305
|
+
gl.bindTexture(gl.TEXTURE_2D, texture1);
|
|
306
|
+
gl.uniform1i(inputFrameLocation, 2);
|
|
307
|
+
gl.uniform2f(texelSizeLocation, texelWidth, 0);
|
|
308
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer2);
|
|
309
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
310
|
+
gl.bindTexture(gl.TEXTURE_2D, texture2);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function cleanUp() {
|
|
314
|
+
gl.deleteFramebuffer(frameBuffer2);
|
|
315
|
+
gl.deleteFramebuffer(frameBuffer1);
|
|
316
|
+
gl.deleteTexture(texture2);
|
|
317
|
+
gl.deleteTexture(texture1);
|
|
318
|
+
gl.deleteProgram(program);
|
|
319
|
+
gl.deleteShader(fragmentShader);
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
render,
|
|
323
|
+
cleanUp
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function buildBlendPass(gl, positionBuffer, texCoordBuffer, canvas) {
|
|
327
|
+
const vertexShaderSource = glsl`#version 300 es
|
|
328
|
+
|
|
329
|
+
in vec2 a_position;
|
|
330
|
+
in vec2 a_texCoord;
|
|
331
|
+
|
|
332
|
+
out vec2 v_texCoord;
|
|
333
|
+
|
|
334
|
+
void main() {
|
|
335
|
+
// Flipping Y is required when rendering to canvas
|
|
336
|
+
gl_Position = vec4(a_position * vec2(1.0, -1.0), 0.0, 1.0);
|
|
337
|
+
v_texCoord = a_texCoord;
|
|
338
|
+
}
|
|
339
|
+
`;
|
|
340
|
+
const fragmentShaderSource = glsl`#version 300 es
|
|
341
|
+
|
|
342
|
+
precision highp float;
|
|
343
|
+
|
|
344
|
+
uniform sampler2D u_inputFrame;
|
|
345
|
+
uniform sampler2D u_personMask;
|
|
346
|
+
uniform sampler2D u_blurredInputFrame;
|
|
347
|
+
uniform vec2 u_coverage;
|
|
348
|
+
|
|
349
|
+
in vec2 v_texCoord;
|
|
350
|
+
|
|
351
|
+
out vec4 outColor;
|
|
352
|
+
|
|
353
|
+
void main() {
|
|
354
|
+
vec3 color = texture(u_inputFrame, v_texCoord).rgb;
|
|
355
|
+
vec3 blurredColor = texture(u_blurredInputFrame, v_texCoord).rgb;
|
|
356
|
+
float personMask = texture(u_personMask, v_texCoord).a;
|
|
357
|
+
personMask = smoothstep(u_coverage.x, u_coverage.y, personMask);
|
|
358
|
+
outColor = vec4(mix(blurredColor, color, personMask), 1.0);
|
|
359
|
+
}
|
|
360
|
+
`;
|
|
361
|
+
const { width: outputWidth, height: outputHeight } = canvas;
|
|
362
|
+
const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
363
|
+
const fragmentShader = compileShader(
|
|
364
|
+
gl,
|
|
365
|
+
gl.FRAGMENT_SHADER,
|
|
366
|
+
fragmentShaderSource
|
|
367
|
+
);
|
|
368
|
+
const program = createPiplelineStageProgram(
|
|
369
|
+
gl,
|
|
370
|
+
vertexShader,
|
|
371
|
+
fragmentShader,
|
|
372
|
+
positionBuffer,
|
|
373
|
+
texCoordBuffer
|
|
374
|
+
);
|
|
375
|
+
const inputFrameLocation = gl.getUniformLocation(program, "u_inputFrame");
|
|
376
|
+
const personMaskLocation = gl.getUniformLocation(program, "u_personMask");
|
|
377
|
+
const blurredInputFrame = gl.getUniformLocation(
|
|
378
|
+
program,
|
|
379
|
+
"u_blurredInputFrame"
|
|
380
|
+
);
|
|
381
|
+
const coverageLocation = gl.getUniformLocation(program, "u_coverage");
|
|
382
|
+
gl.useProgram(program);
|
|
383
|
+
gl.uniform1i(inputFrameLocation, 0);
|
|
384
|
+
gl.uniform1i(personMaskLocation, 1);
|
|
385
|
+
gl.uniform1i(blurredInputFrame, 2);
|
|
386
|
+
gl.uniform2f(coverageLocation, 0, 1);
|
|
387
|
+
function render() {
|
|
388
|
+
gl.viewport(0, 0, outputWidth, outputHeight);
|
|
389
|
+
gl.useProgram(program);
|
|
390
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
391
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
392
|
+
}
|
|
393
|
+
function updateCoverage(coverage) {
|
|
394
|
+
gl.useProgram(program);
|
|
395
|
+
gl.uniform2f(coverageLocation, coverage[0], coverage[1]);
|
|
396
|
+
}
|
|
397
|
+
function cleanUp() {
|
|
398
|
+
gl.deleteProgram(program);
|
|
399
|
+
gl.deleteShader(fragmentShader);
|
|
400
|
+
gl.deleteShader(vertexShader);
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
render,
|
|
404
|
+
updateCoverage,
|
|
405
|
+
cleanUp
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function buildBackgroundImageStage(gl, positionBuffer, texCoordBuffer, personMaskTexture, backgroundImage, canvas, backgroundConfig) {
|
|
409
|
+
const vertexShaderSource = glsl`#version 300 es
|
|
410
|
+
|
|
411
|
+
uniform vec2 u_backgroundScale;
|
|
412
|
+
uniform vec2 u_backgroundOffset;
|
|
413
|
+
|
|
414
|
+
in vec2 a_position;
|
|
415
|
+
in vec2 a_texCoord;
|
|
416
|
+
|
|
417
|
+
out vec2 v_texCoord;
|
|
418
|
+
out vec2 v_backgroundCoord;
|
|
419
|
+
|
|
420
|
+
void main() {
|
|
421
|
+
// Flipping Y is required when rendering to canvas
|
|
422
|
+
gl_Position = vec4(a_position * vec2(1.0, -1.0), 0.0, 1.0);
|
|
423
|
+
v_texCoord = a_texCoord;
|
|
424
|
+
v_backgroundCoord = a_texCoord * u_backgroundScale + u_backgroundOffset;
|
|
425
|
+
}
|
|
426
|
+
`;
|
|
427
|
+
const fragmentShaderSource = glsl`#version 300 es
|
|
428
|
+
|
|
429
|
+
precision highp float;
|
|
430
|
+
|
|
431
|
+
uniform sampler2D u_inputFrame;
|
|
432
|
+
uniform sampler2D u_personMask;
|
|
433
|
+
uniform sampler2D u_background;
|
|
434
|
+
uniform vec2 u_coverage;
|
|
435
|
+
uniform float u_lightWrapping;
|
|
436
|
+
uniform float u_blendMode;
|
|
437
|
+
|
|
438
|
+
in vec2 v_texCoord;
|
|
439
|
+
in vec2 v_backgroundCoord;
|
|
440
|
+
|
|
441
|
+
out vec4 outColor;
|
|
442
|
+
|
|
443
|
+
vec3 screen(vec3 a, vec3 b) {
|
|
444
|
+
return 1.0 - (1.0 - a) * (1.0 - b);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
vec3 linearDodge(vec3 a, vec3 b) {
|
|
448
|
+
return a + b;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
void main() {
|
|
452
|
+
vec3 frameColor = texture(u_inputFrame, v_texCoord).rgb;
|
|
453
|
+
vec3 backgroundColor = texture(u_background, v_backgroundCoord).rgb;
|
|
454
|
+
float personMask = texture(u_personMask, v_texCoord).a;
|
|
455
|
+
float lightWrapMask = 1.0 - max(0.0, personMask - u_coverage.y) / (1.0 - u_coverage.y);
|
|
456
|
+
vec3 lightWrap = u_lightWrapping * lightWrapMask * backgroundColor;
|
|
457
|
+
frameColor = u_blendMode * linearDodge(frameColor, lightWrap) +
|
|
458
|
+
(1.0 - u_blendMode) * screen(frameColor, lightWrap);
|
|
459
|
+
personMask = smoothstep(u_coverage.x, u_coverage.y, personMask);
|
|
460
|
+
outColor = vec4(frameColor * personMask + backgroundColor * (1.0 - personMask), 1.0);
|
|
461
|
+
}
|
|
462
|
+
`;
|
|
463
|
+
const { width: outputWidth, height: outputHeight } = canvas;
|
|
464
|
+
const outputRatio = outputWidth / outputHeight;
|
|
465
|
+
const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
466
|
+
const fragmentShader = compileShader(
|
|
467
|
+
gl,
|
|
468
|
+
gl.FRAGMENT_SHADER,
|
|
469
|
+
fragmentShaderSource
|
|
470
|
+
);
|
|
471
|
+
const program = createPiplelineStageProgram(
|
|
472
|
+
gl,
|
|
473
|
+
vertexShader,
|
|
474
|
+
fragmentShader,
|
|
475
|
+
positionBuffer,
|
|
476
|
+
texCoordBuffer
|
|
477
|
+
);
|
|
478
|
+
const backgroundScaleLocation = gl.getUniformLocation(
|
|
479
|
+
program,
|
|
480
|
+
"u_backgroundScale"
|
|
481
|
+
);
|
|
482
|
+
const backgroundOffsetLocation = gl.getUniformLocation(
|
|
483
|
+
program,
|
|
484
|
+
"u_backgroundOffset"
|
|
485
|
+
);
|
|
486
|
+
const inputFrameLocation = gl.getUniformLocation(program, "u_inputFrame");
|
|
487
|
+
const personMaskLocation = gl.getUniformLocation(program, "u_personMask");
|
|
488
|
+
const backgroundLocation = gl.getUniformLocation(program, "u_background");
|
|
489
|
+
const coverageLocation = gl.getUniformLocation(program, "u_coverage");
|
|
490
|
+
const lightWrappingLocation = gl.getUniformLocation(
|
|
491
|
+
program,
|
|
492
|
+
"u_lightWrapping"
|
|
493
|
+
);
|
|
494
|
+
const blendModeLocation = gl.getUniformLocation(program, "u_blendMode");
|
|
495
|
+
gl.useProgram(program);
|
|
496
|
+
gl.uniform2f(backgroundScaleLocation, 1, 1);
|
|
497
|
+
gl.uniform2f(backgroundOffsetLocation, 0, 0);
|
|
498
|
+
gl.uniform1i(inputFrameLocation, 0);
|
|
499
|
+
gl.uniform1i(personMaskLocation, 1);
|
|
500
|
+
gl.uniform2f(coverageLocation, 0, 1);
|
|
501
|
+
gl.uniform1f(lightWrappingLocation, 0);
|
|
502
|
+
gl.uniform1f(blendModeLocation, 0);
|
|
503
|
+
let backgroundTexture = null;
|
|
504
|
+
if (backgroundImage == null ? void 0 : backgroundImage.complete) {
|
|
505
|
+
updateBackgroundImage(backgroundImage);
|
|
506
|
+
} else if (backgroundImage) {
|
|
507
|
+
backgroundImage.onload = () => {
|
|
508
|
+
updateBackgroundImage(backgroundImage);
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function render() {
|
|
512
|
+
gl.viewport(0, 0, outputWidth, outputHeight);
|
|
513
|
+
gl.useProgram(program);
|
|
514
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
515
|
+
gl.bindTexture(gl.TEXTURE_2D, personMaskTexture);
|
|
516
|
+
if (backgroundTexture !== null) {
|
|
517
|
+
gl.activeTexture(gl.TEXTURE2);
|
|
518
|
+
gl.bindTexture(gl.TEXTURE_2D, backgroundTexture);
|
|
519
|
+
gl.uniform1i(backgroundLocation, 2);
|
|
520
|
+
}
|
|
521
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
522
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
523
|
+
}
|
|
524
|
+
function updateBackgroundImage(backgroundImage2) {
|
|
525
|
+
backgroundTexture = createTexture(
|
|
526
|
+
gl,
|
|
527
|
+
gl.RGBA8,
|
|
528
|
+
backgroundImage2.naturalWidth,
|
|
529
|
+
backgroundImage2.naturalHeight,
|
|
530
|
+
gl.LINEAR,
|
|
531
|
+
gl.LINEAR
|
|
532
|
+
);
|
|
533
|
+
gl.texSubImage2D(
|
|
534
|
+
gl.TEXTURE_2D,
|
|
535
|
+
0,
|
|
536
|
+
0,
|
|
537
|
+
0,
|
|
538
|
+
backgroundImage2.naturalWidth,
|
|
539
|
+
backgroundImage2.naturalHeight,
|
|
540
|
+
gl.RGBA,
|
|
541
|
+
gl.UNSIGNED_BYTE,
|
|
542
|
+
backgroundImage2
|
|
543
|
+
);
|
|
544
|
+
let xOffset = 0;
|
|
545
|
+
let yOffset = 0;
|
|
546
|
+
let backgroundWidth = backgroundImage2.naturalWidth;
|
|
547
|
+
let backgroundHeight = backgroundImage2.naturalHeight;
|
|
548
|
+
const backgroundRatio = backgroundWidth / backgroundHeight;
|
|
549
|
+
if (backgroundRatio < outputRatio) {
|
|
550
|
+
backgroundHeight = backgroundWidth / outputRatio;
|
|
551
|
+
yOffset = (backgroundImage2.naturalHeight - backgroundHeight) / 2;
|
|
552
|
+
} else {
|
|
553
|
+
backgroundWidth = backgroundHeight * outputRatio;
|
|
554
|
+
xOffset = (backgroundImage2.naturalWidth - backgroundWidth) / 2;
|
|
555
|
+
}
|
|
556
|
+
const xScale = backgroundWidth / backgroundImage2.naturalWidth;
|
|
557
|
+
const yScale = backgroundHeight / backgroundImage2.naturalHeight;
|
|
558
|
+
xOffset /= backgroundImage2.naturalWidth;
|
|
559
|
+
yOffset /= backgroundImage2.naturalHeight;
|
|
560
|
+
gl.uniform2f(backgroundScaleLocation, xScale, yScale);
|
|
561
|
+
gl.uniform2f(backgroundOffsetLocation, xOffset, yOffset);
|
|
562
|
+
}
|
|
563
|
+
function updateCoverage(coverage) {
|
|
564
|
+
gl.useProgram(program);
|
|
565
|
+
gl.uniform2f(coverageLocation, coverage[0], coverage[1]);
|
|
566
|
+
}
|
|
567
|
+
function updateLightWrapping(lightWrapping) {
|
|
568
|
+
gl.useProgram(program);
|
|
569
|
+
gl.uniform1f(lightWrappingLocation, lightWrapping);
|
|
570
|
+
}
|
|
571
|
+
function updateBlendMode(blendMode) {
|
|
572
|
+
gl.useProgram(program);
|
|
573
|
+
gl.uniform1f(blendModeLocation, blendMode === "screen" ? 0 : 1);
|
|
574
|
+
}
|
|
575
|
+
function cleanUp() {
|
|
576
|
+
gl.deleteTexture(backgroundTexture);
|
|
577
|
+
gl.deleteProgram(program);
|
|
578
|
+
gl.deleteShader(fragmentShader);
|
|
579
|
+
gl.deleteShader(vertexShader);
|
|
580
|
+
}
|
|
581
|
+
return {
|
|
582
|
+
render,
|
|
583
|
+
updateCoverage,
|
|
584
|
+
updateLightWrapping,
|
|
585
|
+
updateBlendMode,
|
|
586
|
+
cleanUp
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
function buildJointBilateralFilterStage(gl, vertexShader, positionBuffer, texCoordBuffer, inputTexture, segmentationConfig, outputTexture, canvas) {
|
|
590
|
+
const fragmentShaderSource = glsl`#version 300 es
|
|
591
|
+
|
|
592
|
+
precision highp float;
|
|
593
|
+
|
|
594
|
+
uniform sampler2D u_inputFrame;
|
|
595
|
+
uniform sampler2D u_segmentationMask;
|
|
596
|
+
uniform vec2 u_texelSize;
|
|
597
|
+
uniform float u_step;
|
|
598
|
+
uniform float u_radius;
|
|
599
|
+
uniform float u_offset;
|
|
600
|
+
uniform float u_sigmaTexel;
|
|
601
|
+
uniform float u_sigmaColor;
|
|
602
|
+
|
|
603
|
+
in vec2 v_texCoord;
|
|
604
|
+
|
|
605
|
+
out vec4 outColor;
|
|
606
|
+
|
|
607
|
+
float gaussian(float x, float sigma) {
|
|
608
|
+
float coeff = -0.5 / (sigma * sigma * 4.0 + 1.0e-6);
|
|
609
|
+
return exp((x * x) * coeff);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
void main() {
|
|
613
|
+
vec2 centerCoord = v_texCoord;
|
|
614
|
+
vec3 centerColor = texture(u_inputFrame, centerCoord).rgb;
|
|
615
|
+
float newVal = 0.0;
|
|
616
|
+
|
|
617
|
+
float spaceWeight = 0.0;
|
|
618
|
+
float colorWeight = 0.0;
|
|
619
|
+
float totalWeight = 0.0;
|
|
620
|
+
|
|
621
|
+
// Subsample kernel space.
|
|
622
|
+
for (float i = -u_radius + u_offset; i <= u_radius; i += u_step) {
|
|
623
|
+
for (float j = -u_radius + u_offset; j <= u_radius; j += u_step) {
|
|
624
|
+
vec2 shift = vec2(j, i) * u_texelSize;
|
|
625
|
+
vec2 coord = vec2(centerCoord + shift);
|
|
626
|
+
vec3 frameColor = texture(u_inputFrame, coord).rgb;
|
|
627
|
+
float outVal = texture(u_segmentationMask, coord).a;
|
|
628
|
+
|
|
629
|
+
spaceWeight = gaussian(distance(centerCoord, coord), u_sigmaTexel);
|
|
630
|
+
colorWeight = gaussian(distance(centerColor, frameColor), u_sigmaColor);
|
|
631
|
+
totalWeight += spaceWeight * colorWeight;
|
|
632
|
+
|
|
633
|
+
newVal += spaceWeight * colorWeight * outVal;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
newVal /= totalWeight;
|
|
637
|
+
|
|
638
|
+
outColor = vec4(vec3(0.0), newVal);
|
|
639
|
+
}
|
|
640
|
+
`;
|
|
641
|
+
const [segmentationWidth, segmentationHeight] = inputResolutions[segmentationConfig.inputResolution];
|
|
642
|
+
const { width: outputWidth, height: outputHeight } = canvas;
|
|
643
|
+
const texelWidth = 1 / outputWidth;
|
|
644
|
+
const texelHeight = 1 / outputHeight;
|
|
645
|
+
const fragmentShader = compileShader(
|
|
646
|
+
gl,
|
|
647
|
+
gl.FRAGMENT_SHADER,
|
|
648
|
+
fragmentShaderSource
|
|
649
|
+
);
|
|
650
|
+
const program = createPiplelineStageProgram(
|
|
651
|
+
gl,
|
|
652
|
+
vertexShader,
|
|
653
|
+
fragmentShader,
|
|
654
|
+
positionBuffer,
|
|
655
|
+
texCoordBuffer
|
|
656
|
+
);
|
|
657
|
+
const inputFrameLocation = gl.getUniformLocation(program, "u_inputFrame");
|
|
658
|
+
const segmentationMaskLocation = gl.getUniformLocation(
|
|
659
|
+
program,
|
|
660
|
+
"u_segmentationMask"
|
|
661
|
+
);
|
|
662
|
+
const texelSizeLocation = gl.getUniformLocation(program, "u_texelSize");
|
|
663
|
+
const stepLocation = gl.getUniformLocation(program, "u_step");
|
|
664
|
+
const radiusLocation = gl.getUniformLocation(program, "u_radius");
|
|
665
|
+
const offsetLocation = gl.getUniformLocation(program, "u_offset");
|
|
666
|
+
const sigmaTexelLocation = gl.getUniformLocation(program, "u_sigmaTexel");
|
|
667
|
+
const sigmaColorLocation = gl.getUniformLocation(program, "u_sigmaColor");
|
|
668
|
+
const frameBuffer = gl.createFramebuffer();
|
|
669
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
670
|
+
gl.framebufferTexture2D(
|
|
671
|
+
gl.FRAMEBUFFER,
|
|
672
|
+
gl.COLOR_ATTACHMENT0,
|
|
673
|
+
gl.TEXTURE_2D,
|
|
674
|
+
outputTexture,
|
|
675
|
+
0
|
|
676
|
+
);
|
|
677
|
+
gl.useProgram(program);
|
|
678
|
+
gl.uniform1i(inputFrameLocation, 0);
|
|
679
|
+
gl.uniform1i(segmentationMaskLocation, 1);
|
|
680
|
+
gl.uniform2f(texelSizeLocation, texelWidth, texelHeight);
|
|
681
|
+
updateSigmaSpace(0);
|
|
682
|
+
updateSigmaColor(0);
|
|
683
|
+
function render() {
|
|
684
|
+
gl.viewport(0, 0, outputWidth, outputHeight);
|
|
685
|
+
gl.useProgram(program);
|
|
686
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
687
|
+
gl.bindTexture(gl.TEXTURE_2D, inputTexture);
|
|
688
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
689
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
690
|
+
}
|
|
691
|
+
function updateSigmaSpace(sigmaSpace) {
|
|
692
|
+
sigmaSpace *= Math.max(
|
|
693
|
+
outputWidth / segmentationWidth,
|
|
694
|
+
outputHeight / segmentationHeight
|
|
695
|
+
);
|
|
696
|
+
const kSparsityFactor = 0.66;
|
|
697
|
+
const sparsity = Math.max(1, Math.sqrt(sigmaSpace) * kSparsityFactor);
|
|
698
|
+
const step = sparsity;
|
|
699
|
+
const radius = sigmaSpace;
|
|
700
|
+
const offset = step > 1 ? step * 0.5 : 0;
|
|
701
|
+
const sigmaTexel = Math.max(texelWidth, texelHeight) * sigmaSpace;
|
|
702
|
+
gl.useProgram(program);
|
|
703
|
+
gl.uniform1f(stepLocation, step);
|
|
704
|
+
gl.uniform1f(radiusLocation, radius);
|
|
705
|
+
gl.uniform1f(offsetLocation, offset);
|
|
706
|
+
gl.uniform1f(sigmaTexelLocation, sigmaTexel);
|
|
707
|
+
}
|
|
708
|
+
function updateSigmaColor(sigmaColor) {
|
|
709
|
+
gl.useProgram(program);
|
|
710
|
+
gl.uniform1f(sigmaColorLocation, sigmaColor);
|
|
711
|
+
}
|
|
712
|
+
function cleanUp() {
|
|
713
|
+
gl.deleteFramebuffer(frameBuffer);
|
|
714
|
+
gl.deleteProgram(program);
|
|
715
|
+
gl.deleteShader(fragmentShader);
|
|
716
|
+
}
|
|
717
|
+
return {
|
|
718
|
+
render,
|
|
719
|
+
updateSigmaSpace,
|
|
720
|
+
updateSigmaColor,
|
|
721
|
+
cleanUp
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
function buildLoadSegmentationStage(gl, vertexShader, positionBuffer, texCoordBuffer, segmentationConfig, tflite, outputTexture) {
|
|
725
|
+
const fragmentShaderSource = glsl`#version 300 es
|
|
726
|
+
|
|
727
|
+
precision highp float;
|
|
728
|
+
|
|
729
|
+
uniform sampler2D u_inputSegmentation;
|
|
730
|
+
|
|
731
|
+
in vec2 v_texCoord;
|
|
732
|
+
|
|
733
|
+
out vec4 outColor;
|
|
734
|
+
|
|
735
|
+
void main() {
|
|
736
|
+
float segmentation = texture(u_inputSegmentation, v_texCoord).r;
|
|
737
|
+
outColor = vec4(vec3(0.0), segmentation);
|
|
738
|
+
}
|
|
739
|
+
`;
|
|
740
|
+
const tfliteOutputMemoryOffset = tflite._getOutputMemoryOffset() / 4;
|
|
741
|
+
const [segmentationWidth, segmentationHeight] = inputResolutions[segmentationConfig.inputResolution];
|
|
742
|
+
const fragmentShader = compileShader(
|
|
743
|
+
gl,
|
|
744
|
+
gl.FRAGMENT_SHADER,
|
|
745
|
+
fragmentShaderSource
|
|
746
|
+
);
|
|
747
|
+
const program = createPiplelineStageProgram(
|
|
748
|
+
gl,
|
|
749
|
+
vertexShader,
|
|
750
|
+
fragmentShader,
|
|
751
|
+
positionBuffer,
|
|
752
|
+
texCoordBuffer
|
|
753
|
+
);
|
|
754
|
+
const inputLocation = gl.getUniformLocation(program, "u_inputSegmentation");
|
|
755
|
+
const inputTexture = createTexture(
|
|
756
|
+
gl,
|
|
757
|
+
gl.R32F,
|
|
758
|
+
segmentationWidth,
|
|
759
|
+
segmentationHeight
|
|
760
|
+
);
|
|
761
|
+
const frameBuffer = gl.createFramebuffer();
|
|
762
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
763
|
+
gl.framebufferTexture2D(
|
|
764
|
+
gl.FRAMEBUFFER,
|
|
765
|
+
gl.COLOR_ATTACHMENT0,
|
|
766
|
+
gl.TEXTURE_2D,
|
|
767
|
+
outputTexture,
|
|
768
|
+
0
|
|
769
|
+
);
|
|
770
|
+
gl.useProgram(program);
|
|
771
|
+
gl.uniform1i(inputLocation, 1);
|
|
772
|
+
function render() {
|
|
773
|
+
gl.viewport(0, 0, segmentationWidth, segmentationHeight);
|
|
774
|
+
gl.useProgram(program);
|
|
775
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
776
|
+
gl.bindTexture(gl.TEXTURE_2D, inputTexture);
|
|
777
|
+
gl.texSubImage2D(
|
|
778
|
+
gl.TEXTURE_2D,
|
|
779
|
+
0,
|
|
780
|
+
0,
|
|
781
|
+
0,
|
|
782
|
+
segmentationWidth,
|
|
783
|
+
segmentationHeight,
|
|
784
|
+
gl.RED,
|
|
785
|
+
gl.FLOAT,
|
|
786
|
+
tflite.HEAPF32,
|
|
787
|
+
tfliteOutputMemoryOffset
|
|
788
|
+
);
|
|
789
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
790
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
791
|
+
}
|
|
792
|
+
function cleanUp() {
|
|
793
|
+
gl.deleteFramebuffer(frameBuffer);
|
|
794
|
+
gl.deleteTexture(inputTexture);
|
|
795
|
+
gl.deleteProgram(program);
|
|
796
|
+
gl.deleteShader(fragmentShader);
|
|
797
|
+
}
|
|
798
|
+
return { render, cleanUp };
|
|
799
|
+
}
|
|
800
|
+
function buildResizingStage(timerWorker, gl, vertexShader, positionBuffer, texCoordBuffer, segmentationConfig, tflite) {
|
|
801
|
+
const fragmentShaderSource = glsl`#version 300 es
|
|
802
|
+
|
|
803
|
+
precision highp float;
|
|
804
|
+
|
|
805
|
+
uniform sampler2D u_inputFrame;
|
|
806
|
+
|
|
807
|
+
in vec2 v_texCoord;
|
|
808
|
+
|
|
809
|
+
out vec4 outColor;
|
|
810
|
+
|
|
811
|
+
void main() {
|
|
812
|
+
outColor = texture(u_inputFrame, v_texCoord);
|
|
813
|
+
}
|
|
814
|
+
`;
|
|
815
|
+
const tfliteInputMemoryOffset = tflite._getInputMemoryOffset() / 4;
|
|
816
|
+
const [outputWidth, outputHeight] = inputResolutions[segmentationConfig.inputResolution];
|
|
817
|
+
const outputPixelCount = outputWidth * outputHeight;
|
|
818
|
+
const fragmentShader = compileShader(
|
|
819
|
+
gl,
|
|
820
|
+
gl.FRAGMENT_SHADER,
|
|
821
|
+
fragmentShaderSource
|
|
822
|
+
);
|
|
823
|
+
const program = createPiplelineStageProgram(
|
|
824
|
+
gl,
|
|
825
|
+
vertexShader,
|
|
826
|
+
fragmentShader,
|
|
827
|
+
positionBuffer,
|
|
828
|
+
texCoordBuffer
|
|
829
|
+
);
|
|
830
|
+
const inputFrameLocation = gl.getUniformLocation(program, "u_inputFrame");
|
|
831
|
+
const outputTexture = createTexture(gl, gl.RGBA8, outputWidth, outputHeight);
|
|
832
|
+
const frameBuffer = gl.createFramebuffer();
|
|
833
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
834
|
+
gl.framebufferTexture2D(
|
|
835
|
+
gl.FRAMEBUFFER,
|
|
836
|
+
gl.COLOR_ATTACHMENT0,
|
|
837
|
+
gl.TEXTURE_2D,
|
|
838
|
+
outputTexture,
|
|
839
|
+
0
|
|
840
|
+
);
|
|
841
|
+
const outputPixels = new Uint8Array(outputPixelCount * 4);
|
|
842
|
+
gl.useProgram(program);
|
|
843
|
+
gl.uniform1i(inputFrameLocation, 0);
|
|
844
|
+
async function render() {
|
|
845
|
+
gl.viewport(0, 0, outputWidth, outputHeight);
|
|
846
|
+
gl.useProgram(program);
|
|
847
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
848
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
849
|
+
const readPixelsPromise = readPixelsAsync(
|
|
850
|
+
timerWorker,
|
|
851
|
+
gl,
|
|
852
|
+
0,
|
|
853
|
+
0,
|
|
854
|
+
outputWidth,
|
|
855
|
+
outputHeight,
|
|
856
|
+
gl.RGBA,
|
|
857
|
+
gl.UNSIGNED_BYTE,
|
|
858
|
+
outputPixels
|
|
859
|
+
);
|
|
860
|
+
if (segmentationConfig.deferInputResizing)
|
|
861
|
+
;
|
|
862
|
+
else {
|
|
863
|
+
await readPixelsPromise;
|
|
864
|
+
}
|
|
865
|
+
for (let i = 0; i < outputPixelCount; i++) {
|
|
866
|
+
const tfliteIndex = tfliteInputMemoryOffset + i * 3;
|
|
867
|
+
const outputIndex = i * 4;
|
|
868
|
+
tflite.HEAPF32[tfliteIndex] = outputPixels[outputIndex] / 255;
|
|
869
|
+
tflite.HEAPF32[tfliteIndex + 1] = outputPixels[outputIndex + 1] / 255;
|
|
870
|
+
tflite.HEAPF32[tfliteIndex + 2] = outputPixels[outputIndex + 2] / 255;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
function cleanUp() {
|
|
874
|
+
gl.deleteFramebuffer(frameBuffer);
|
|
875
|
+
gl.deleteTexture(outputTexture);
|
|
876
|
+
gl.deleteProgram(program);
|
|
877
|
+
gl.deleteShader(fragmentShader);
|
|
878
|
+
}
|
|
879
|
+
return { render, cleanUp };
|
|
880
|
+
}
|
|
881
|
+
function buildSoftmaxStage(gl, vertexShader, positionBuffer, texCoordBuffer, segmentationConfig, tflite, outputTexture) {
|
|
882
|
+
const fragmentShaderSource = glsl`#version 300 es
|
|
883
|
+
|
|
884
|
+
precision highp float;
|
|
885
|
+
|
|
886
|
+
uniform sampler2D u_inputSegmentation;
|
|
887
|
+
|
|
888
|
+
in vec2 v_texCoord;
|
|
889
|
+
|
|
890
|
+
out vec4 outColor;
|
|
891
|
+
|
|
892
|
+
void main() {
|
|
893
|
+
vec2 segmentation = texture(u_inputSegmentation, v_texCoord).rg;
|
|
894
|
+
float shift = max(segmentation.r, segmentation.g);
|
|
895
|
+
float backgroundExp = exp(segmentation.r - shift);
|
|
896
|
+
float personExp = exp(segmentation.g - shift);
|
|
897
|
+
outColor = vec4(vec3(0.0), personExp / (backgroundExp + personExp));
|
|
898
|
+
}
|
|
899
|
+
`;
|
|
900
|
+
const tfliteOutputMemoryOffset = tflite._getOutputMemoryOffset() / 4;
|
|
901
|
+
const [segmentationWidth, segmentationHeight] = inputResolutions[segmentationConfig.inputResolution];
|
|
902
|
+
const fragmentShader = compileShader(
|
|
903
|
+
gl,
|
|
904
|
+
gl.FRAGMENT_SHADER,
|
|
905
|
+
fragmentShaderSource
|
|
906
|
+
);
|
|
907
|
+
const program = createPiplelineStageProgram(
|
|
908
|
+
gl,
|
|
909
|
+
vertexShader,
|
|
910
|
+
fragmentShader,
|
|
911
|
+
positionBuffer,
|
|
912
|
+
texCoordBuffer
|
|
913
|
+
);
|
|
914
|
+
const inputLocation = gl.getUniformLocation(program, "u_inputSegmentation");
|
|
915
|
+
const inputTexture = createTexture(
|
|
916
|
+
gl,
|
|
917
|
+
gl.RG32F,
|
|
918
|
+
segmentationWidth,
|
|
919
|
+
segmentationHeight
|
|
920
|
+
);
|
|
921
|
+
const frameBuffer = gl.createFramebuffer();
|
|
922
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
923
|
+
gl.framebufferTexture2D(
|
|
924
|
+
gl.FRAMEBUFFER,
|
|
925
|
+
gl.COLOR_ATTACHMENT0,
|
|
926
|
+
gl.TEXTURE_2D,
|
|
927
|
+
outputTexture,
|
|
928
|
+
0
|
|
929
|
+
);
|
|
930
|
+
gl.useProgram(program);
|
|
931
|
+
gl.uniform1i(inputLocation, 1);
|
|
932
|
+
function render() {
|
|
933
|
+
gl.viewport(0, 0, segmentationWidth, segmentationHeight);
|
|
934
|
+
gl.useProgram(program);
|
|
935
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
936
|
+
gl.bindTexture(gl.TEXTURE_2D, inputTexture);
|
|
937
|
+
gl.texSubImage2D(
|
|
938
|
+
gl.TEXTURE_2D,
|
|
939
|
+
0,
|
|
940
|
+
0,
|
|
941
|
+
0,
|
|
942
|
+
segmentationWidth,
|
|
943
|
+
segmentationHeight,
|
|
944
|
+
gl.RG,
|
|
945
|
+
gl.FLOAT,
|
|
946
|
+
tflite.HEAPF32,
|
|
947
|
+
tfliteOutputMemoryOffset
|
|
948
|
+
);
|
|
949
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
950
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
951
|
+
}
|
|
952
|
+
function cleanUp() {
|
|
953
|
+
gl.deleteFramebuffer(frameBuffer);
|
|
954
|
+
gl.deleteTexture(inputTexture);
|
|
955
|
+
gl.deleteProgram(program);
|
|
956
|
+
gl.deleteShader(fragmentShader);
|
|
957
|
+
}
|
|
958
|
+
return { render, cleanUp };
|
|
959
|
+
}
|
|
960
|
+
function buildWebGL2Pipeline(sourcePlayback, backgroundConfig, segmentationConfig, canvas, tflite, timerWorker) {
|
|
961
|
+
const vertexShaderSource = glsl`#version 300 es
|
|
962
|
+
|
|
963
|
+
in vec2 a_position;
|
|
964
|
+
in vec2 a_texCoord;
|
|
965
|
+
|
|
966
|
+
out vec2 v_texCoord;
|
|
967
|
+
|
|
968
|
+
void main() {
|
|
969
|
+
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
970
|
+
v_texCoord = a_texCoord;
|
|
971
|
+
}
|
|
972
|
+
`;
|
|
973
|
+
const { width: frameWidth, height: frameHeight } = sourcePlayback;
|
|
974
|
+
const [segmentationWidth, segmentationHeight] = inputResolutions[segmentationConfig.inputResolution];
|
|
975
|
+
const gl = canvas.getContext("webgl2");
|
|
976
|
+
const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
|
|
977
|
+
const vertexArray = gl.createVertexArray();
|
|
978
|
+
gl.bindVertexArray(vertexArray);
|
|
979
|
+
const positionBuffer = gl.createBuffer();
|
|
980
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
981
|
+
gl.bufferData(
|
|
982
|
+
gl.ARRAY_BUFFER,
|
|
983
|
+
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
|
|
984
|
+
gl.STATIC_DRAW
|
|
985
|
+
);
|
|
986
|
+
const texCoordBuffer = gl.createBuffer();
|
|
987
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
|
988
|
+
gl.bufferData(
|
|
989
|
+
gl.ARRAY_BUFFER,
|
|
990
|
+
new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]),
|
|
991
|
+
gl.STATIC_DRAW
|
|
992
|
+
);
|
|
993
|
+
const inputFrameTexture = gl.createTexture();
|
|
994
|
+
gl.bindTexture(gl.TEXTURE_2D, inputFrameTexture);
|
|
995
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
996
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
997
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
998
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
999
|
+
const segmentationTexture = createTexture(
|
|
1000
|
+
gl,
|
|
1001
|
+
gl.RGBA8,
|
|
1002
|
+
segmentationWidth,
|
|
1003
|
+
segmentationHeight
|
|
1004
|
+
);
|
|
1005
|
+
const personMaskTexture = createTexture(
|
|
1006
|
+
gl,
|
|
1007
|
+
gl.RGBA8,
|
|
1008
|
+
frameWidth,
|
|
1009
|
+
frameHeight
|
|
1010
|
+
);
|
|
1011
|
+
const resizingStage = buildResizingStage(
|
|
1012
|
+
timerWorker,
|
|
1013
|
+
gl,
|
|
1014
|
+
vertexShader,
|
|
1015
|
+
positionBuffer,
|
|
1016
|
+
texCoordBuffer,
|
|
1017
|
+
segmentationConfig,
|
|
1018
|
+
tflite
|
|
1019
|
+
);
|
|
1020
|
+
const loadSegmentationStage = segmentationConfig.model === "meet" ? buildSoftmaxStage(
|
|
1021
|
+
gl,
|
|
1022
|
+
vertexShader,
|
|
1023
|
+
positionBuffer,
|
|
1024
|
+
texCoordBuffer,
|
|
1025
|
+
segmentationConfig,
|
|
1026
|
+
tflite,
|
|
1027
|
+
segmentationTexture
|
|
1028
|
+
) : buildLoadSegmentationStage(
|
|
1029
|
+
gl,
|
|
1030
|
+
vertexShader,
|
|
1031
|
+
positionBuffer,
|
|
1032
|
+
texCoordBuffer,
|
|
1033
|
+
segmentationConfig,
|
|
1034
|
+
tflite,
|
|
1035
|
+
segmentationTexture
|
|
1036
|
+
);
|
|
1037
|
+
const jointBilateralFilterStage = buildJointBilateralFilterStage(
|
|
1038
|
+
gl,
|
|
1039
|
+
vertexShader,
|
|
1040
|
+
positionBuffer,
|
|
1041
|
+
texCoordBuffer,
|
|
1042
|
+
segmentationTexture,
|
|
1043
|
+
segmentationConfig,
|
|
1044
|
+
personMaskTexture,
|
|
1045
|
+
canvas
|
|
1046
|
+
);
|
|
1047
|
+
const backgroundStage = backgroundConfig.type === "blur" ? buildBackgroundBlurStage(
|
|
1048
|
+
gl,
|
|
1049
|
+
vertexShader,
|
|
1050
|
+
positionBuffer,
|
|
1051
|
+
texCoordBuffer,
|
|
1052
|
+
personMaskTexture,
|
|
1053
|
+
canvas,
|
|
1054
|
+
backgroundConfig
|
|
1055
|
+
) : buildBackgroundImageStage(
|
|
1056
|
+
gl,
|
|
1057
|
+
positionBuffer,
|
|
1058
|
+
texCoordBuffer,
|
|
1059
|
+
personMaskTexture,
|
|
1060
|
+
backgroundConfig.backgroundImage,
|
|
1061
|
+
canvas
|
|
1062
|
+
);
|
|
1063
|
+
async function render() {
|
|
1064
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
1065
|
+
gl.bindTexture(gl.TEXTURE_2D, inputFrameTexture);
|
|
1066
|
+
gl.texImage2D(
|
|
1067
|
+
gl.TEXTURE_2D,
|
|
1068
|
+
0,
|
|
1069
|
+
gl.RGBA,
|
|
1070
|
+
gl.RGBA,
|
|
1071
|
+
gl.UNSIGNED_BYTE,
|
|
1072
|
+
sourcePlayback.htmlElement
|
|
1073
|
+
);
|
|
1074
|
+
gl.bindVertexArray(vertexArray);
|
|
1075
|
+
await resizingStage.render();
|
|
1076
|
+
tflite._runInference();
|
|
1077
|
+
loadSegmentationStage.render();
|
|
1078
|
+
jointBilateralFilterStage.render();
|
|
1079
|
+
backgroundStage.render();
|
|
1080
|
+
}
|
|
1081
|
+
function updatePostProcessingConfig(postProcessingConfig) {
|
|
1082
|
+
jointBilateralFilterStage.updateSigmaSpace(
|
|
1083
|
+
postProcessingConfig.jointBilateralFilter.sigmaSpace
|
|
1084
|
+
);
|
|
1085
|
+
jointBilateralFilterStage.updateSigmaColor(
|
|
1086
|
+
postProcessingConfig.jointBilateralFilter.sigmaColor
|
|
1087
|
+
);
|
|
1088
|
+
if (backgroundConfig.type === "image") {
|
|
1089
|
+
const backgroundImageStage = backgroundStage;
|
|
1090
|
+
backgroundImageStage.updateCoverage(postProcessingConfig.coverage);
|
|
1091
|
+
backgroundImageStage.updateLightWrapping(
|
|
1092
|
+
postProcessingConfig.lightWrapping
|
|
1093
|
+
);
|
|
1094
|
+
backgroundImageStage.updateBlendMode(postProcessingConfig.blendMode);
|
|
1095
|
+
} else if (backgroundConfig.type === "blur") {
|
|
1096
|
+
const backgroundBlurStage = backgroundStage;
|
|
1097
|
+
backgroundBlurStage.updateCoverage(postProcessingConfig.coverage);
|
|
1098
|
+
} else {
|
|
1099
|
+
const backgroundImageStage = backgroundStage;
|
|
1100
|
+
backgroundImageStage.updateCoverage([0, 0.9999]);
|
|
1101
|
+
backgroundImageStage.updateLightWrapping(0);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
function cleanUp() {
|
|
1105
|
+
backgroundStage.cleanUp();
|
|
1106
|
+
jointBilateralFilterStage.cleanUp();
|
|
1107
|
+
loadSegmentationStage.cleanUp();
|
|
1108
|
+
resizingStage.cleanUp();
|
|
1109
|
+
gl.deleteTexture(personMaskTexture);
|
|
1110
|
+
gl.deleteTexture(segmentationTexture);
|
|
1111
|
+
gl.deleteTexture(inputFrameTexture);
|
|
1112
|
+
gl.deleteBuffer(texCoordBuffer);
|
|
1113
|
+
gl.deleteBuffer(positionBuffer);
|
|
1114
|
+
gl.deleteVertexArray(vertexArray);
|
|
1115
|
+
gl.deleteShader(vertexShader);
|
|
1116
|
+
}
|
|
1117
|
+
return { render, updatePostProcessingConfig, cleanUp };
|
|
1118
|
+
}
|
|
1119
|
+
const BROWSER_ALIASES_MAP = {
|
|
1120
|
+
"Amazon Silk": "amazon_silk",
|
|
1121
|
+
"Android Browser": "android",
|
|
1122
|
+
Bada: "bada",
|
|
1123
|
+
BlackBerry: "blackberry",
|
|
1124
|
+
Chrome: "chrome",
|
|
1125
|
+
Chromium: "chromium",
|
|
1126
|
+
Electron: "electron",
|
|
1127
|
+
Epiphany: "epiphany",
|
|
1128
|
+
Firefox: "firefox",
|
|
1129
|
+
Focus: "focus",
|
|
1130
|
+
Generic: "generic",
|
|
1131
|
+
"Google Search": "google_search",
|
|
1132
|
+
Googlebot: "googlebot",
|
|
1133
|
+
"Internet Explorer": "ie",
|
|
1134
|
+
"K-Meleon": "k_meleon",
|
|
1135
|
+
Maxthon: "maxthon",
|
|
1136
|
+
"Microsoft Edge": "edge",
|
|
1137
|
+
"MZ Browser": "mz",
|
|
1138
|
+
"NAVER Whale Browser": "naver",
|
|
1139
|
+
Opera: "opera",
|
|
1140
|
+
"Opera Coast": "opera_coast",
|
|
1141
|
+
PhantomJS: "phantomjs",
|
|
1142
|
+
Puffin: "puffin",
|
|
1143
|
+
QupZilla: "qupzilla",
|
|
1144
|
+
QQ: "qq",
|
|
1145
|
+
QQLite: "qqlite",
|
|
1146
|
+
Safari: "safari",
|
|
1147
|
+
Sailfish: "sailfish",
|
|
1148
|
+
"Samsung Internet for Android": "samsung_internet",
|
|
1149
|
+
SeaMonkey: "seamonkey",
|
|
1150
|
+
Sleipnir: "sleipnir",
|
|
1151
|
+
Swing: "swing",
|
|
1152
|
+
Tizen: "tizen",
|
|
1153
|
+
"UC Browser": "uc",
|
|
1154
|
+
Vivaldi: "vivaldi",
|
|
1155
|
+
"WebOS Browser": "webos",
|
|
1156
|
+
WeChat: "wechat",
|
|
1157
|
+
"Yandex Browser": "yandex",
|
|
1158
|
+
Roku: "roku"
|
|
1159
|
+
};
|
|
1160
|
+
const BROWSER_MAP = {
|
|
1161
|
+
amazon_silk: "Amazon Silk",
|
|
1162
|
+
android: "Android Browser",
|
|
1163
|
+
bada: "Bada",
|
|
1164
|
+
blackberry: "BlackBerry",
|
|
1165
|
+
chrome: "Chrome",
|
|
1166
|
+
chromium: "Chromium",
|
|
1167
|
+
electron: "Electron",
|
|
1168
|
+
epiphany: "Epiphany",
|
|
1169
|
+
firefox: "Firefox",
|
|
1170
|
+
focus: "Focus",
|
|
1171
|
+
generic: "Generic",
|
|
1172
|
+
googlebot: "Googlebot",
|
|
1173
|
+
google_search: "Google Search",
|
|
1174
|
+
ie: "Internet Explorer",
|
|
1175
|
+
k_meleon: "K-Meleon",
|
|
1176
|
+
maxthon: "Maxthon",
|
|
1177
|
+
edge: "Microsoft Edge",
|
|
1178
|
+
mz: "MZ Browser",
|
|
1179
|
+
naver: "NAVER Whale Browser",
|
|
1180
|
+
opera: "Opera",
|
|
1181
|
+
opera_coast: "Opera Coast",
|
|
1182
|
+
phantomjs: "PhantomJS",
|
|
1183
|
+
puffin: "Puffin",
|
|
1184
|
+
qupzilla: "QupZilla",
|
|
1185
|
+
qq: "QQ Browser",
|
|
1186
|
+
qqlite: "QQ Browser Lite",
|
|
1187
|
+
safari: "Safari",
|
|
1188
|
+
sailfish: "Sailfish",
|
|
1189
|
+
samsung_internet: "Samsung Internet for Android",
|
|
1190
|
+
seamonkey: "SeaMonkey",
|
|
1191
|
+
sleipnir: "Sleipnir",
|
|
1192
|
+
swing: "Swing",
|
|
1193
|
+
tizen: "Tizen",
|
|
1194
|
+
uc: "UC Browser",
|
|
1195
|
+
vivaldi: "Vivaldi",
|
|
1196
|
+
webos: "WebOS Browser",
|
|
1197
|
+
wechat: "WeChat",
|
|
1198
|
+
yandex: "Yandex Browser"
|
|
1199
|
+
};
|
|
1200
|
+
const PLATFORMS_MAP = {
|
|
1201
|
+
tablet: "tablet",
|
|
1202
|
+
mobile: "mobile",
|
|
1203
|
+
desktop: "desktop",
|
|
1204
|
+
tv: "tv"
|
|
1205
|
+
};
|
|
1206
|
+
const OS_MAP = {
|
|
1207
|
+
WindowsPhone: "Windows Phone",
|
|
1208
|
+
Windows: "Windows",
|
|
1209
|
+
MacOS: "macOS",
|
|
1210
|
+
iOS: "iOS",
|
|
1211
|
+
Android: "Android",
|
|
1212
|
+
WebOS: "WebOS",
|
|
1213
|
+
BlackBerry: "BlackBerry",
|
|
1214
|
+
Bada: "Bada",
|
|
1215
|
+
Tizen: "Tizen",
|
|
1216
|
+
Linux: "Linux",
|
|
1217
|
+
ChromeOS: "Chrome OS",
|
|
1218
|
+
PlayStation4: "PlayStation 4",
|
|
1219
|
+
Roku: "Roku"
|
|
1220
|
+
};
|
|
1221
|
+
const ENGINE_MAP = {
|
|
1222
|
+
EdgeHTML: "EdgeHTML",
|
|
1223
|
+
Blink: "Blink",
|
|
1224
|
+
Trident: "Trident",
|
|
1225
|
+
Presto: "Presto",
|
|
1226
|
+
Gecko: "Gecko",
|
|
1227
|
+
WebKit: "WebKit"
|
|
1228
|
+
};
|
|
1229
|
+
class Utils {
|
|
1230
|
+
static getFirstMatch(regexp, ua) {
|
|
1231
|
+
const match = ua.match(regexp);
|
|
1232
|
+
return match && match.length > 0 && match[1] || "";
|
|
1233
|
+
}
|
|
1234
|
+
static getSecondMatch(regexp, ua) {
|
|
1235
|
+
const match = ua.match(regexp);
|
|
1236
|
+
return match && match.length > 1 && match[2] || "";
|
|
1237
|
+
}
|
|
1238
|
+
static matchAndReturnConst(regexp, ua, _const) {
|
|
1239
|
+
if (regexp.test(ua)) {
|
|
1240
|
+
return _const;
|
|
1241
|
+
}
|
|
1242
|
+
return void 0;
|
|
1243
|
+
}
|
|
1244
|
+
static getWindowsVersionName(version) {
|
|
1245
|
+
switch (version) {
|
|
1246
|
+
case "NT":
|
|
1247
|
+
return "NT";
|
|
1248
|
+
case "XP":
|
|
1249
|
+
return "XP";
|
|
1250
|
+
case "NT 5.0":
|
|
1251
|
+
return "2000";
|
|
1252
|
+
case "NT 5.1":
|
|
1253
|
+
return "XP";
|
|
1254
|
+
case "NT 5.2":
|
|
1255
|
+
return "2003";
|
|
1256
|
+
case "NT 6.0":
|
|
1257
|
+
return "Vista";
|
|
1258
|
+
case "NT 6.1":
|
|
1259
|
+
return "7";
|
|
1260
|
+
case "NT 6.2":
|
|
1261
|
+
return "8";
|
|
1262
|
+
case "NT 6.3":
|
|
1263
|
+
return "8.1";
|
|
1264
|
+
case "NT 10.0":
|
|
1265
|
+
return "10";
|
|
1266
|
+
default:
|
|
1267
|
+
return void 0;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
static getMacOSVersionName(version) {
|
|
1271
|
+
const v = version.split(".").splice(0, 2).map((s) => parseInt(s, 10) || 0);
|
|
1272
|
+
v.push(0);
|
|
1273
|
+
if (v[0] !== 10)
|
|
1274
|
+
return void 0;
|
|
1275
|
+
switch (v[1]) {
|
|
1276
|
+
case 5:
|
|
1277
|
+
return "Leopard";
|
|
1278
|
+
case 6:
|
|
1279
|
+
return "Snow Leopard";
|
|
1280
|
+
case 7:
|
|
1281
|
+
return "Lion";
|
|
1282
|
+
case 8:
|
|
1283
|
+
return "Mountain Lion";
|
|
1284
|
+
case 9:
|
|
1285
|
+
return "Mavericks";
|
|
1286
|
+
case 10:
|
|
1287
|
+
return "Yosemite";
|
|
1288
|
+
case 11:
|
|
1289
|
+
return "El Capitan";
|
|
1290
|
+
case 12:
|
|
1291
|
+
return "Sierra";
|
|
1292
|
+
case 13:
|
|
1293
|
+
return "High Sierra";
|
|
1294
|
+
case 14:
|
|
1295
|
+
return "Mojave";
|
|
1296
|
+
case 15:
|
|
1297
|
+
return "Catalina";
|
|
1298
|
+
default:
|
|
1299
|
+
return void 0;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
static getAndroidVersionName(version) {
|
|
1303
|
+
const v = version.split(".").splice(0, 2).map((s) => parseInt(s, 10) || 0);
|
|
1304
|
+
v.push(0);
|
|
1305
|
+
if (v[0] === 1 && v[1] < 5)
|
|
1306
|
+
return void 0;
|
|
1307
|
+
if (v[0] === 1 && v[1] < 6)
|
|
1308
|
+
return "Cupcake";
|
|
1309
|
+
if (v[0] === 1 && v[1] >= 6)
|
|
1310
|
+
return "Donut";
|
|
1311
|
+
if (v[0] === 2 && v[1] < 2)
|
|
1312
|
+
return "Eclair";
|
|
1313
|
+
if (v[0] === 2 && v[1] === 2)
|
|
1314
|
+
return "Froyo";
|
|
1315
|
+
if (v[0] === 2 && v[1] > 2)
|
|
1316
|
+
return "Gingerbread";
|
|
1317
|
+
if (v[0] === 3)
|
|
1318
|
+
return "Honeycomb";
|
|
1319
|
+
if (v[0] === 4 && v[1] < 1)
|
|
1320
|
+
return "Ice Cream Sandwich";
|
|
1321
|
+
if (v[0] === 4 && v[1] < 4)
|
|
1322
|
+
return "Jelly Bean";
|
|
1323
|
+
if (v[0] === 4 && v[1] >= 4)
|
|
1324
|
+
return "KitKat";
|
|
1325
|
+
if (v[0] === 5)
|
|
1326
|
+
return "Lollipop";
|
|
1327
|
+
if (v[0] === 6)
|
|
1328
|
+
return "Marshmallow";
|
|
1329
|
+
if (v[0] === 7)
|
|
1330
|
+
return "Nougat";
|
|
1331
|
+
if (v[0] === 8)
|
|
1332
|
+
return "Oreo";
|
|
1333
|
+
if (v[0] === 9)
|
|
1334
|
+
return "Pie";
|
|
1335
|
+
return void 0;
|
|
1336
|
+
}
|
|
1337
|
+
static getVersionPrecision(version) {
|
|
1338
|
+
return version.split(".").length;
|
|
1339
|
+
}
|
|
1340
|
+
static compareVersions(versionA, versionB, isLoose = false) {
|
|
1341
|
+
const versionAPrecision = Utils.getVersionPrecision(versionA);
|
|
1342
|
+
const versionBPrecision = Utils.getVersionPrecision(versionB);
|
|
1343
|
+
let precision = Math.max(versionAPrecision, versionBPrecision);
|
|
1344
|
+
let lastPrecision = 0;
|
|
1345
|
+
const chunks = Utils.map([versionA, versionB], (version) => {
|
|
1346
|
+
const delta = precision - Utils.getVersionPrecision(version);
|
|
1347
|
+
const _version = version + new Array(delta + 1).join(".0");
|
|
1348
|
+
return Utils.map(_version.split("."), (chunk) => new Array(20 - chunk.length).join("0") + chunk).reverse();
|
|
1349
|
+
});
|
|
1350
|
+
if (isLoose) {
|
|
1351
|
+
lastPrecision = precision - Math.min(versionAPrecision, versionBPrecision);
|
|
1352
|
+
}
|
|
1353
|
+
precision -= 1;
|
|
1354
|
+
while (precision >= lastPrecision) {
|
|
1355
|
+
if (chunks[0][precision] > chunks[1][precision]) {
|
|
1356
|
+
return 1;
|
|
1357
|
+
}
|
|
1358
|
+
if (chunks[0][precision] === chunks[1][precision]) {
|
|
1359
|
+
if (precision === lastPrecision) {
|
|
1360
|
+
return 0;
|
|
1361
|
+
}
|
|
1362
|
+
precision -= 1;
|
|
1363
|
+
} else if (chunks[0][precision] < chunks[1][precision]) {
|
|
1364
|
+
return -1;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
return void 0;
|
|
1368
|
+
}
|
|
1369
|
+
static map(arr, iterator) {
|
|
1370
|
+
const result = [];
|
|
1371
|
+
let i;
|
|
1372
|
+
if (Array.prototype.map) {
|
|
1373
|
+
return Array.prototype.map.call(arr, iterator);
|
|
1374
|
+
}
|
|
1375
|
+
for (i = 0; i < arr.length; i += 1) {
|
|
1376
|
+
result.push(iterator(arr[i]));
|
|
1377
|
+
}
|
|
1378
|
+
return result;
|
|
1379
|
+
}
|
|
1380
|
+
static find(arr, predicate) {
|
|
1381
|
+
let i;
|
|
1382
|
+
let l;
|
|
1383
|
+
if (Array.prototype.find) {
|
|
1384
|
+
return Array.prototype.find.call(arr, predicate);
|
|
1385
|
+
}
|
|
1386
|
+
for (i = 0, l = arr.length; i < l; i += 1) {
|
|
1387
|
+
const value = arr[i];
|
|
1388
|
+
if (predicate(value, i)) {
|
|
1389
|
+
return value;
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
return void 0;
|
|
1393
|
+
}
|
|
1394
|
+
static assign(obj, ...assigners) {
|
|
1395
|
+
const result = obj;
|
|
1396
|
+
let i;
|
|
1397
|
+
let l;
|
|
1398
|
+
if (Object.assign) {
|
|
1399
|
+
return Object.assign(obj, ...assigners);
|
|
1400
|
+
}
|
|
1401
|
+
for (i = 0, l = assigners.length; i < l; i += 1) {
|
|
1402
|
+
const assigner = assigners[i];
|
|
1403
|
+
if (typeof assigner === "object" && assigner !== null) {
|
|
1404
|
+
const keys = Object.keys(assigner);
|
|
1405
|
+
keys.forEach((key) => {
|
|
1406
|
+
result[key] = assigner[key];
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
return obj;
|
|
1411
|
+
}
|
|
1412
|
+
static getBrowserAlias(browserName) {
|
|
1413
|
+
return BROWSER_ALIASES_MAP[browserName];
|
|
1414
|
+
}
|
|
1415
|
+
static getBrowserTypeByAlias(browserAlias) {
|
|
1416
|
+
return BROWSER_MAP[browserAlias] || "";
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
const commonVersionIdentifier = /version\/(\d+(\.?_?\d+)+)/i;
|
|
1420
|
+
const browsersList = [
|
|
1421
|
+
{
|
|
1422
|
+
test: [/googlebot/i],
|
|
1423
|
+
describe(ua) {
|
|
1424
|
+
const browser = {
|
|
1425
|
+
name: "Googlebot"
|
|
1426
|
+
};
|
|
1427
|
+
const version = Utils.getFirstMatch(/googlebot\/(\d+(\.\d+))/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1428
|
+
if (version) {
|
|
1429
|
+
browser.version = version;
|
|
1430
|
+
}
|
|
1431
|
+
return browser;
|
|
1432
|
+
}
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
test: [/opera/i],
|
|
1436
|
+
describe(ua) {
|
|
1437
|
+
const browser = {
|
|
1438
|
+
name: "Opera"
|
|
1439
|
+
};
|
|
1440
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1441
|
+
if (version) {
|
|
1442
|
+
browser.version = version;
|
|
1443
|
+
}
|
|
1444
|
+
return browser;
|
|
1445
|
+
}
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
test: [/opr\/|opios/i],
|
|
1449
|
+
describe(ua) {
|
|
1450
|
+
const browser = {
|
|
1451
|
+
name: "Opera"
|
|
1452
|
+
};
|
|
1453
|
+
const version = Utils.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1454
|
+
if (version) {
|
|
1455
|
+
browser.version = version;
|
|
1456
|
+
}
|
|
1457
|
+
return browser;
|
|
1458
|
+
}
|
|
1459
|
+
},
|
|
1460
|
+
{
|
|
1461
|
+
test: [/SamsungBrowser/i],
|
|
1462
|
+
describe(ua) {
|
|
1463
|
+
const browser = {
|
|
1464
|
+
name: "Samsung Internet for Android"
|
|
1465
|
+
};
|
|
1466
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1467
|
+
if (version) {
|
|
1468
|
+
browser.version = version;
|
|
1469
|
+
}
|
|
1470
|
+
return browser;
|
|
1471
|
+
}
|
|
1472
|
+
},
|
|
1473
|
+
{
|
|
1474
|
+
test: [/Whale/i],
|
|
1475
|
+
describe(ua) {
|
|
1476
|
+
const browser = {
|
|
1477
|
+
name: "NAVER Whale Browser"
|
|
1478
|
+
};
|
|
1479
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i, ua);
|
|
1480
|
+
if (version) {
|
|
1481
|
+
browser.version = version;
|
|
1482
|
+
}
|
|
1483
|
+
return browser;
|
|
1484
|
+
}
|
|
1485
|
+
},
|
|
1486
|
+
{
|
|
1487
|
+
test: [/MZBrowser/i],
|
|
1488
|
+
describe(ua) {
|
|
1489
|
+
const browser = {
|
|
1490
|
+
name: "MZ Browser"
|
|
1491
|
+
};
|
|
1492
|
+
const version = Utils.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1493
|
+
if (version) {
|
|
1494
|
+
browser.version = version;
|
|
1495
|
+
}
|
|
1496
|
+
return browser;
|
|
1497
|
+
}
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
test: [/focus/i],
|
|
1501
|
+
describe(ua) {
|
|
1502
|
+
const browser = {
|
|
1503
|
+
name: "Focus"
|
|
1504
|
+
};
|
|
1505
|
+
const version = Utils.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1506
|
+
if (version) {
|
|
1507
|
+
browser.version = version;
|
|
1508
|
+
}
|
|
1509
|
+
return browser;
|
|
1510
|
+
}
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
test: [/swing/i],
|
|
1514
|
+
describe(ua) {
|
|
1515
|
+
const browser = {
|
|
1516
|
+
name: "Swing"
|
|
1517
|
+
};
|
|
1518
|
+
const version = Utils.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1519
|
+
if (version) {
|
|
1520
|
+
browser.version = version;
|
|
1521
|
+
}
|
|
1522
|
+
return browser;
|
|
1523
|
+
}
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
test: [/coast/i],
|
|
1527
|
+
describe(ua) {
|
|
1528
|
+
const browser = {
|
|
1529
|
+
name: "Opera Coast"
|
|
1530
|
+
};
|
|
1531
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1532
|
+
if (version) {
|
|
1533
|
+
browser.version = version;
|
|
1534
|
+
}
|
|
1535
|
+
return browser;
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1538
|
+
{
|
|
1539
|
+
test: [/opt\/\d+(?:.?_?\d+)+/i],
|
|
1540
|
+
describe(ua) {
|
|
1541
|
+
const browser = {
|
|
1542
|
+
name: "Opera Touch"
|
|
1543
|
+
};
|
|
1544
|
+
const version = Utils.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1545
|
+
if (version) {
|
|
1546
|
+
browser.version = version;
|
|
1547
|
+
}
|
|
1548
|
+
return browser;
|
|
1549
|
+
}
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
test: [/yabrowser/i],
|
|
1553
|
+
describe(ua) {
|
|
1554
|
+
const browser = {
|
|
1555
|
+
name: "Yandex Browser"
|
|
1556
|
+
};
|
|
1557
|
+
const version = Utils.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1558
|
+
if (version) {
|
|
1559
|
+
browser.version = version;
|
|
1560
|
+
}
|
|
1561
|
+
return browser;
|
|
1562
|
+
}
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
test: [/ucbrowser/i],
|
|
1566
|
+
describe(ua) {
|
|
1567
|
+
const browser = {
|
|
1568
|
+
name: "UC Browser"
|
|
1569
|
+
};
|
|
1570
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1571
|
+
if (version) {
|
|
1572
|
+
browser.version = version;
|
|
1573
|
+
}
|
|
1574
|
+
return browser;
|
|
1575
|
+
}
|
|
1576
|
+
},
|
|
1577
|
+
{
|
|
1578
|
+
test: [/Maxthon|mxios/i],
|
|
1579
|
+
describe(ua) {
|
|
1580
|
+
const browser = {
|
|
1581
|
+
name: "Maxthon"
|
|
1582
|
+
};
|
|
1583
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1584
|
+
if (version) {
|
|
1585
|
+
browser.version = version;
|
|
1586
|
+
}
|
|
1587
|
+
return browser;
|
|
1588
|
+
}
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
test: [/epiphany/i],
|
|
1592
|
+
describe(ua) {
|
|
1593
|
+
const browser = {
|
|
1594
|
+
name: "Epiphany"
|
|
1595
|
+
};
|
|
1596
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1597
|
+
if (version) {
|
|
1598
|
+
browser.version = version;
|
|
1599
|
+
}
|
|
1600
|
+
return browser;
|
|
1601
|
+
}
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
test: [/puffin/i],
|
|
1605
|
+
describe(ua) {
|
|
1606
|
+
const browser = {
|
|
1607
|
+
name: "Puffin"
|
|
1608
|
+
};
|
|
1609
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1610
|
+
if (version) {
|
|
1611
|
+
browser.version = version;
|
|
1612
|
+
}
|
|
1613
|
+
return browser;
|
|
1614
|
+
}
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
test: [/sleipnir/i],
|
|
1618
|
+
describe(ua) {
|
|
1619
|
+
const browser = {
|
|
1620
|
+
name: "Sleipnir"
|
|
1621
|
+
};
|
|
1622
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1623
|
+
if (version) {
|
|
1624
|
+
browser.version = version;
|
|
1625
|
+
}
|
|
1626
|
+
return browser;
|
|
1627
|
+
}
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
test: [/k-meleon/i],
|
|
1631
|
+
describe(ua) {
|
|
1632
|
+
const browser = {
|
|
1633
|
+
name: "K-Meleon"
|
|
1634
|
+
};
|
|
1635
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1636
|
+
if (version) {
|
|
1637
|
+
browser.version = version;
|
|
1638
|
+
}
|
|
1639
|
+
return browser;
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1642
|
+
{
|
|
1643
|
+
test: [/micromessenger/i],
|
|
1644
|
+
describe(ua) {
|
|
1645
|
+
const browser = {
|
|
1646
|
+
name: "WeChat"
|
|
1647
|
+
};
|
|
1648
|
+
const version = Utils.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1649
|
+
if (version) {
|
|
1650
|
+
browser.version = version;
|
|
1651
|
+
}
|
|
1652
|
+
return browser;
|
|
1653
|
+
}
|
|
1654
|
+
},
|
|
1655
|
+
{
|
|
1656
|
+
test: [/qqbrowser/i],
|
|
1657
|
+
describe(ua) {
|
|
1658
|
+
const browser = {
|
|
1659
|
+
name: /qqbrowserlite/i.test(ua) ? "QQ Browser Lite" : "QQ Browser"
|
|
1660
|
+
};
|
|
1661
|
+
const version = Utils.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1662
|
+
if (version) {
|
|
1663
|
+
browser.version = version;
|
|
1664
|
+
}
|
|
1665
|
+
return browser;
|
|
1666
|
+
}
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
test: [/msie|trident/i],
|
|
1670
|
+
describe(ua) {
|
|
1671
|
+
const browser = {
|
|
1672
|
+
name: "Internet Explorer"
|
|
1673
|
+
};
|
|
1674
|
+
const version = Utils.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i, ua);
|
|
1675
|
+
if (version) {
|
|
1676
|
+
browser.version = version;
|
|
1677
|
+
}
|
|
1678
|
+
return browser;
|
|
1679
|
+
}
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
test: [/\sedg\//i],
|
|
1683
|
+
describe(ua) {
|
|
1684
|
+
const browser = {
|
|
1685
|
+
name: "Microsoft Edge"
|
|
1686
|
+
};
|
|
1687
|
+
const version = Utils.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1688
|
+
if (version) {
|
|
1689
|
+
browser.version = version;
|
|
1690
|
+
}
|
|
1691
|
+
return browser;
|
|
1692
|
+
}
|
|
1693
|
+
},
|
|
1694
|
+
{
|
|
1695
|
+
test: [/edg([ea]|ios)/i],
|
|
1696
|
+
describe(ua) {
|
|
1697
|
+
const browser = {
|
|
1698
|
+
name: "Microsoft Edge"
|
|
1699
|
+
};
|
|
1700
|
+
const version = Utils.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1701
|
+
if (version) {
|
|
1702
|
+
browser.version = version;
|
|
1703
|
+
}
|
|
1704
|
+
return browser;
|
|
1705
|
+
}
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
test: [/vivaldi/i],
|
|
1709
|
+
describe(ua) {
|
|
1710
|
+
const browser = {
|
|
1711
|
+
name: "Vivaldi"
|
|
1712
|
+
};
|
|
1713
|
+
const version = Utils.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1714
|
+
if (version) {
|
|
1715
|
+
browser.version = version;
|
|
1716
|
+
}
|
|
1717
|
+
return browser;
|
|
1718
|
+
}
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
test: [/seamonkey/i],
|
|
1722
|
+
describe(ua) {
|
|
1723
|
+
const browser = {
|
|
1724
|
+
name: "SeaMonkey"
|
|
1725
|
+
};
|
|
1726
|
+
const version = Utils.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1727
|
+
if (version) {
|
|
1728
|
+
browser.version = version;
|
|
1729
|
+
}
|
|
1730
|
+
return browser;
|
|
1731
|
+
}
|
|
1732
|
+
},
|
|
1733
|
+
{
|
|
1734
|
+
test: [/sailfish/i],
|
|
1735
|
+
describe(ua) {
|
|
1736
|
+
const browser = {
|
|
1737
|
+
name: "Sailfish"
|
|
1738
|
+
};
|
|
1739
|
+
const version = Utils.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i, ua);
|
|
1740
|
+
if (version) {
|
|
1741
|
+
browser.version = version;
|
|
1742
|
+
}
|
|
1743
|
+
return browser;
|
|
1744
|
+
}
|
|
1745
|
+
},
|
|
1746
|
+
{
|
|
1747
|
+
test: [/silk/i],
|
|
1748
|
+
describe(ua) {
|
|
1749
|
+
const browser = {
|
|
1750
|
+
name: "Amazon Silk"
|
|
1751
|
+
};
|
|
1752
|
+
const version = Utils.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1753
|
+
if (version) {
|
|
1754
|
+
browser.version = version;
|
|
1755
|
+
}
|
|
1756
|
+
return browser;
|
|
1757
|
+
}
|
|
1758
|
+
},
|
|
1759
|
+
{
|
|
1760
|
+
test: [/phantom/i],
|
|
1761
|
+
describe(ua) {
|
|
1762
|
+
const browser = {
|
|
1763
|
+
name: "PhantomJS"
|
|
1764
|
+
};
|
|
1765
|
+
const version = Utils.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1766
|
+
if (version) {
|
|
1767
|
+
browser.version = version;
|
|
1768
|
+
}
|
|
1769
|
+
return browser;
|
|
1770
|
+
}
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
test: [/slimerjs/i],
|
|
1774
|
+
describe(ua) {
|
|
1775
|
+
const browser = {
|
|
1776
|
+
name: "SlimerJS"
|
|
1777
|
+
};
|
|
1778
|
+
const version = Utils.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1779
|
+
if (version) {
|
|
1780
|
+
browser.version = version;
|
|
1781
|
+
}
|
|
1782
|
+
return browser;
|
|
1783
|
+
}
|
|
1784
|
+
},
|
|
1785
|
+
{
|
|
1786
|
+
test: [/blackberry|\bbb\d+/i, /rim\stablet/i],
|
|
1787
|
+
describe(ua) {
|
|
1788
|
+
const browser = {
|
|
1789
|
+
name: "BlackBerry"
|
|
1790
|
+
};
|
|
1791
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1792
|
+
if (version) {
|
|
1793
|
+
browser.version = version;
|
|
1794
|
+
}
|
|
1795
|
+
return browser;
|
|
1796
|
+
}
|
|
1797
|
+
},
|
|
1798
|
+
{
|
|
1799
|
+
test: [/(web|hpw)[o0]s/i],
|
|
1800
|
+
describe(ua) {
|
|
1801
|
+
const browser = {
|
|
1802
|
+
name: "WebOS Browser"
|
|
1803
|
+
};
|
|
1804
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua) || Utils.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1805
|
+
if (version) {
|
|
1806
|
+
browser.version = version;
|
|
1807
|
+
}
|
|
1808
|
+
return browser;
|
|
1809
|
+
}
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
test: [/bada/i],
|
|
1813
|
+
describe(ua) {
|
|
1814
|
+
const browser = {
|
|
1815
|
+
name: "Bada"
|
|
1816
|
+
};
|
|
1817
|
+
const version = Utils.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1818
|
+
if (version) {
|
|
1819
|
+
browser.version = version;
|
|
1820
|
+
}
|
|
1821
|
+
return browser;
|
|
1822
|
+
}
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
test: [/tizen/i],
|
|
1826
|
+
describe(ua) {
|
|
1827
|
+
const browser = {
|
|
1828
|
+
name: "Tizen"
|
|
1829
|
+
};
|
|
1830
|
+
const version = Utils.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1831
|
+
if (version) {
|
|
1832
|
+
browser.version = version;
|
|
1833
|
+
}
|
|
1834
|
+
return browser;
|
|
1835
|
+
}
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
test: [/qupzilla/i],
|
|
1839
|
+
describe(ua) {
|
|
1840
|
+
const browser = {
|
|
1841
|
+
name: "QupZilla"
|
|
1842
|
+
};
|
|
1843
|
+
const version = Utils.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1844
|
+
if (version) {
|
|
1845
|
+
browser.version = version;
|
|
1846
|
+
}
|
|
1847
|
+
return browser;
|
|
1848
|
+
}
|
|
1849
|
+
},
|
|
1850
|
+
{
|
|
1851
|
+
test: [/firefox|iceweasel|fxios/i],
|
|
1852
|
+
describe(ua) {
|
|
1853
|
+
const browser = {
|
|
1854
|
+
name: "Firefox"
|
|
1855
|
+
};
|
|
1856
|
+
const version = Utils.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1857
|
+
if (version) {
|
|
1858
|
+
browser.version = version;
|
|
1859
|
+
}
|
|
1860
|
+
return browser;
|
|
1861
|
+
}
|
|
1862
|
+
},
|
|
1863
|
+
{
|
|
1864
|
+
test: [/electron/i],
|
|
1865
|
+
describe(ua) {
|
|
1866
|
+
const browser = {
|
|
1867
|
+
name: "Electron"
|
|
1868
|
+
};
|
|
1869
|
+
const version = Utils.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1870
|
+
if (version) {
|
|
1871
|
+
browser.version = version;
|
|
1872
|
+
}
|
|
1873
|
+
return browser;
|
|
1874
|
+
}
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
test: [/MiuiBrowser/i],
|
|
1878
|
+
describe(ua) {
|
|
1879
|
+
const browser = {
|
|
1880
|
+
name: "Miui"
|
|
1881
|
+
};
|
|
1882
|
+
const version = Utils.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i, ua);
|
|
1883
|
+
if (version) {
|
|
1884
|
+
browser.version = version;
|
|
1885
|
+
}
|
|
1886
|
+
return browser;
|
|
1887
|
+
}
|
|
1888
|
+
},
|
|
1889
|
+
{
|
|
1890
|
+
test: [/chromium/i],
|
|
1891
|
+
describe(ua) {
|
|
1892
|
+
const browser = {
|
|
1893
|
+
name: "Chromium"
|
|
1894
|
+
};
|
|
1895
|
+
const version = Utils.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i, ua) || Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1896
|
+
if (version) {
|
|
1897
|
+
browser.version = version;
|
|
1898
|
+
}
|
|
1899
|
+
return browser;
|
|
1900
|
+
}
|
|
1901
|
+
},
|
|
1902
|
+
{
|
|
1903
|
+
test: [/chrome|crios|crmo/i],
|
|
1904
|
+
describe(ua) {
|
|
1905
|
+
const browser = {
|
|
1906
|
+
name: "Chrome"
|
|
1907
|
+
};
|
|
1908
|
+
const version = Utils.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1909
|
+
if (version) {
|
|
1910
|
+
browser.version = version;
|
|
1911
|
+
}
|
|
1912
|
+
return browser;
|
|
1913
|
+
}
|
|
1914
|
+
},
|
|
1915
|
+
{
|
|
1916
|
+
test: [/GSA/i],
|
|
1917
|
+
describe(ua) {
|
|
1918
|
+
const browser = {
|
|
1919
|
+
name: "Google Search"
|
|
1920
|
+
};
|
|
1921
|
+
const version = Utils.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i, ua);
|
|
1922
|
+
if (version) {
|
|
1923
|
+
browser.version = version;
|
|
1924
|
+
}
|
|
1925
|
+
return browser;
|
|
1926
|
+
}
|
|
1927
|
+
},
|
|
1928
|
+
{
|
|
1929
|
+
test(parser) {
|
|
1930
|
+
const notLikeAndroid = !parser.test(/like android/i);
|
|
1931
|
+
const butAndroid = parser.test(/android/i);
|
|
1932
|
+
return notLikeAndroid && butAndroid;
|
|
1933
|
+
},
|
|
1934
|
+
describe(ua) {
|
|
1935
|
+
const browser = {
|
|
1936
|
+
name: "Android Browser"
|
|
1937
|
+
};
|
|
1938
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1939
|
+
if (version) {
|
|
1940
|
+
browser.version = version;
|
|
1941
|
+
}
|
|
1942
|
+
return browser;
|
|
1943
|
+
}
|
|
1944
|
+
},
|
|
1945
|
+
{
|
|
1946
|
+
test: [/playstation 4/i],
|
|
1947
|
+
describe(ua) {
|
|
1948
|
+
const browser = {
|
|
1949
|
+
name: "PlayStation 4"
|
|
1950
|
+
};
|
|
1951
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1952
|
+
if (version) {
|
|
1953
|
+
browser.version = version;
|
|
1954
|
+
}
|
|
1955
|
+
return browser;
|
|
1956
|
+
}
|
|
1957
|
+
},
|
|
1958
|
+
{
|
|
1959
|
+
test: [/safari|applewebkit/i],
|
|
1960
|
+
describe(ua) {
|
|
1961
|
+
const browser = {
|
|
1962
|
+
name: "Safari"
|
|
1963
|
+
};
|
|
1964
|
+
const version = Utils.getFirstMatch(commonVersionIdentifier, ua);
|
|
1965
|
+
if (version) {
|
|
1966
|
+
browser.version = version;
|
|
1967
|
+
}
|
|
1968
|
+
return browser;
|
|
1969
|
+
}
|
|
1970
|
+
},
|
|
1971
|
+
{
|
|
1972
|
+
test: [/.*/i],
|
|
1973
|
+
describe(ua) {
|
|
1974
|
+
const regexpWithoutDeviceSpec = /^(.*)\/(.*) /;
|
|
1975
|
+
const regexpWithDeviceSpec = /^(.*)\/(.*)[ \t]\((.*)/;
|
|
1976
|
+
const hasDeviceSpec = ua.search("\\(") !== -1;
|
|
1977
|
+
const regexp = hasDeviceSpec ? regexpWithDeviceSpec : regexpWithoutDeviceSpec;
|
|
1978
|
+
return {
|
|
1979
|
+
name: Utils.getFirstMatch(regexp, ua),
|
|
1980
|
+
version: Utils.getSecondMatch(regexp, ua)
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
];
|
|
1985
|
+
var osParsersList = [
|
|
1986
|
+
{
|
|
1987
|
+
test: [/Roku\/DVP/],
|
|
1988
|
+
describe(ua) {
|
|
1989
|
+
const version = Utils.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i, ua);
|
|
1990
|
+
return {
|
|
1991
|
+
name: OS_MAP.Roku,
|
|
1992
|
+
version
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
},
|
|
1996
|
+
{
|
|
1997
|
+
test: [/windows phone/i],
|
|
1998
|
+
describe(ua) {
|
|
1999
|
+
const version = Utils.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i, ua);
|
|
2000
|
+
return {
|
|
2001
|
+
name: OS_MAP.WindowsPhone,
|
|
2002
|
+
version
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
},
|
|
2006
|
+
{
|
|
2007
|
+
test: [/windows /i],
|
|
2008
|
+
describe(ua) {
|
|
2009
|
+
const version = Utils.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i, ua);
|
|
2010
|
+
const versionName = Utils.getWindowsVersionName(version);
|
|
2011
|
+
return {
|
|
2012
|
+
name: OS_MAP.Windows,
|
|
2013
|
+
version,
|
|
2014
|
+
versionName
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
},
|
|
2018
|
+
{
|
|
2019
|
+
test: [/Macintosh(.*?) FxiOS(.*?)\//],
|
|
2020
|
+
describe(ua) {
|
|
2021
|
+
const result = {
|
|
2022
|
+
name: OS_MAP.iOS
|
|
2023
|
+
};
|
|
2024
|
+
const version = Utils.getSecondMatch(/(Version\/)(\d[\d.]+)/, ua);
|
|
2025
|
+
if (version) {
|
|
2026
|
+
result.version = version;
|
|
2027
|
+
}
|
|
2028
|
+
return result;
|
|
2029
|
+
}
|
|
2030
|
+
},
|
|
2031
|
+
{
|
|
2032
|
+
test: [/macintosh/i],
|
|
2033
|
+
describe(ua) {
|
|
2034
|
+
const version = Utils.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i, ua).replace(/[_\s]/g, ".");
|
|
2035
|
+
const versionName = Utils.getMacOSVersionName(version);
|
|
2036
|
+
const os = {
|
|
2037
|
+
name: OS_MAP.MacOS,
|
|
2038
|
+
version
|
|
2039
|
+
};
|
|
2040
|
+
if (versionName) {
|
|
2041
|
+
os.versionName = versionName;
|
|
2042
|
+
}
|
|
2043
|
+
return os;
|
|
2044
|
+
}
|
|
2045
|
+
},
|
|
2046
|
+
{
|
|
2047
|
+
test: [/(ipod|iphone|ipad)/i],
|
|
2048
|
+
describe(ua) {
|
|
2049
|
+
const version = Utils.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i, ua).replace(/[_\s]/g, ".");
|
|
2050
|
+
return {
|
|
2051
|
+
name: OS_MAP.iOS,
|
|
2052
|
+
version
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
},
|
|
2056
|
+
{
|
|
2057
|
+
test(parser) {
|
|
2058
|
+
const notLikeAndroid = !parser.test(/like android/i);
|
|
2059
|
+
const butAndroid = parser.test(/android/i);
|
|
2060
|
+
return notLikeAndroid && butAndroid;
|
|
2061
|
+
},
|
|
2062
|
+
describe(ua) {
|
|
2063
|
+
const version = Utils.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i, ua);
|
|
2064
|
+
const versionName = Utils.getAndroidVersionName(version);
|
|
2065
|
+
const os = {
|
|
2066
|
+
name: OS_MAP.Android,
|
|
2067
|
+
version
|
|
2068
|
+
};
|
|
2069
|
+
if (versionName) {
|
|
2070
|
+
os.versionName = versionName;
|
|
2071
|
+
}
|
|
2072
|
+
return os;
|
|
2073
|
+
}
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
test: [/(web|hpw)[o0]s/i],
|
|
2077
|
+
describe(ua) {
|
|
2078
|
+
const version = Utils.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i, ua);
|
|
2079
|
+
const os = {
|
|
2080
|
+
name: OS_MAP.WebOS
|
|
2081
|
+
};
|
|
2082
|
+
if (version && version.length) {
|
|
2083
|
+
os.version = version;
|
|
2084
|
+
}
|
|
2085
|
+
return os;
|
|
2086
|
+
}
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
2089
|
+
test: [/blackberry|\bbb\d+/i, /rim\stablet/i],
|
|
2090
|
+
describe(ua) {
|
|
2091
|
+
const version = Utils.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i, ua) || Utils.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i, ua) || Utils.getFirstMatch(/\bbb(\d+)/i, ua);
|
|
2092
|
+
return {
|
|
2093
|
+
name: OS_MAP.BlackBerry,
|
|
2094
|
+
version
|
|
2095
|
+
};
|
|
2096
|
+
}
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
test: [/bada/i],
|
|
2100
|
+
describe(ua) {
|
|
2101
|
+
const version = Utils.getFirstMatch(/bada\/(\d+(\.\d+)*)/i, ua);
|
|
2102
|
+
return {
|
|
2103
|
+
name: OS_MAP.Bada,
|
|
2104
|
+
version
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
},
|
|
2108
|
+
{
|
|
2109
|
+
test: [/tizen/i],
|
|
2110
|
+
describe(ua) {
|
|
2111
|
+
const version = Utils.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i, ua);
|
|
2112
|
+
return {
|
|
2113
|
+
name: OS_MAP.Tizen,
|
|
2114
|
+
version
|
|
2115
|
+
};
|
|
2116
|
+
}
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
test: [/linux/i],
|
|
2120
|
+
describe() {
|
|
2121
|
+
return {
|
|
2122
|
+
name: OS_MAP.Linux
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
},
|
|
2126
|
+
{
|
|
2127
|
+
test: [/CrOS/],
|
|
2128
|
+
describe() {
|
|
2129
|
+
return {
|
|
2130
|
+
name: OS_MAP.ChromeOS
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2133
|
+
},
|
|
2134
|
+
{
|
|
2135
|
+
test: [/PlayStation 4/],
|
|
2136
|
+
describe(ua) {
|
|
2137
|
+
const version = Utils.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i, ua);
|
|
2138
|
+
return {
|
|
2139
|
+
name: OS_MAP.PlayStation4,
|
|
2140
|
+
version
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
];
|
|
2145
|
+
var platformParsersList = [
|
|
2146
|
+
{
|
|
2147
|
+
test: [/googlebot/i],
|
|
2148
|
+
describe() {
|
|
2149
|
+
return {
|
|
2150
|
+
type: "bot",
|
|
2151
|
+
vendor: "Google"
|
|
2152
|
+
};
|
|
2153
|
+
}
|
|
2154
|
+
},
|
|
2155
|
+
{
|
|
2156
|
+
test: [/huawei/i],
|
|
2157
|
+
describe(ua) {
|
|
2158
|
+
const model = Utils.getFirstMatch(/(can-l01)/i, ua) && "Nova";
|
|
2159
|
+
const platform = {
|
|
2160
|
+
type: PLATFORMS_MAP.mobile,
|
|
2161
|
+
vendor: "Huawei"
|
|
2162
|
+
};
|
|
2163
|
+
if (model) {
|
|
2164
|
+
platform.model = model;
|
|
2165
|
+
}
|
|
2166
|
+
return platform;
|
|
2167
|
+
}
|
|
2168
|
+
},
|
|
2169
|
+
{
|
|
2170
|
+
test: [/nexus\s*(?:7|8|9|10).*/i],
|
|
2171
|
+
describe() {
|
|
2172
|
+
return {
|
|
2173
|
+
type: PLATFORMS_MAP.tablet,
|
|
2174
|
+
vendor: "Nexus"
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
},
|
|
2178
|
+
{
|
|
2179
|
+
test: [/ipad/i],
|
|
2180
|
+
describe() {
|
|
2181
|
+
return {
|
|
2182
|
+
type: PLATFORMS_MAP.tablet,
|
|
2183
|
+
vendor: "Apple",
|
|
2184
|
+
model: "iPad"
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
},
|
|
2188
|
+
{
|
|
2189
|
+
test: [/Macintosh(.*?) FxiOS(.*?)\//],
|
|
2190
|
+
describe() {
|
|
2191
|
+
return {
|
|
2192
|
+
type: PLATFORMS_MAP.tablet,
|
|
2193
|
+
vendor: "Apple",
|
|
2194
|
+
model: "iPad"
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
},
|
|
2198
|
+
{
|
|
2199
|
+
test: [/kftt build/i],
|
|
2200
|
+
describe() {
|
|
2201
|
+
return {
|
|
2202
|
+
type: PLATFORMS_MAP.tablet,
|
|
2203
|
+
vendor: "Amazon",
|
|
2204
|
+
model: "Kindle Fire HD 7"
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
},
|
|
2208
|
+
{
|
|
2209
|
+
test: [/silk/i],
|
|
2210
|
+
describe() {
|
|
2211
|
+
return {
|
|
2212
|
+
type: PLATFORMS_MAP.tablet,
|
|
2213
|
+
vendor: "Amazon"
|
|
2214
|
+
};
|
|
2215
|
+
}
|
|
2216
|
+
},
|
|
2217
|
+
{
|
|
2218
|
+
test: [/tablet(?! pc)/i],
|
|
2219
|
+
describe() {
|
|
2220
|
+
return {
|
|
2221
|
+
type: PLATFORMS_MAP.tablet
|
|
2222
|
+
};
|
|
2223
|
+
}
|
|
2224
|
+
},
|
|
2225
|
+
{
|
|
2226
|
+
test(parser) {
|
|
2227
|
+
const iDevice = parser.test(/ipod|iphone/i);
|
|
2228
|
+
const likeIDevice = parser.test(/like (ipod|iphone)/i);
|
|
2229
|
+
return iDevice && !likeIDevice;
|
|
2230
|
+
},
|
|
2231
|
+
describe(ua) {
|
|
2232
|
+
const model = Utils.getFirstMatch(/(ipod|iphone)/i, ua);
|
|
2233
|
+
return {
|
|
2234
|
+
type: PLATFORMS_MAP.mobile,
|
|
2235
|
+
vendor: "Apple",
|
|
2236
|
+
model
|
|
2237
|
+
};
|
|
2238
|
+
}
|
|
2239
|
+
},
|
|
2240
|
+
{
|
|
2241
|
+
test: [/nexus\s*[0-6].*/i, /galaxy nexus/i],
|
|
2242
|
+
describe() {
|
|
2243
|
+
return {
|
|
2244
|
+
type: PLATFORMS_MAP.mobile,
|
|
2245
|
+
vendor: "Nexus"
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
2248
|
+
},
|
|
2249
|
+
{
|
|
2250
|
+
test: [/[^-]mobi/i],
|
|
2251
|
+
describe() {
|
|
2252
|
+
return {
|
|
2253
|
+
type: PLATFORMS_MAP.mobile
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
},
|
|
2257
|
+
{
|
|
2258
|
+
test(parser) {
|
|
2259
|
+
return parser.getBrowserName(true) === "blackberry";
|
|
2260
|
+
},
|
|
2261
|
+
describe() {
|
|
2262
|
+
return {
|
|
2263
|
+
type: PLATFORMS_MAP.mobile,
|
|
2264
|
+
vendor: "BlackBerry"
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
},
|
|
2268
|
+
{
|
|
2269
|
+
test(parser) {
|
|
2270
|
+
return parser.getBrowserName(true) === "bada";
|
|
2271
|
+
},
|
|
2272
|
+
describe() {
|
|
2273
|
+
return {
|
|
2274
|
+
type: PLATFORMS_MAP.mobile
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
2277
|
+
},
|
|
2278
|
+
{
|
|
2279
|
+
test(parser) {
|
|
2280
|
+
return parser.getBrowserName() === "windows phone";
|
|
2281
|
+
},
|
|
2282
|
+
describe() {
|
|
2283
|
+
return {
|
|
2284
|
+
type: PLATFORMS_MAP.mobile,
|
|
2285
|
+
vendor: "Microsoft"
|
|
2286
|
+
};
|
|
2287
|
+
}
|
|
2288
|
+
},
|
|
2289
|
+
{
|
|
2290
|
+
test(parser) {
|
|
2291
|
+
const osMajorVersion = Number(String(parser.getOSVersion()).split(".")[0]);
|
|
2292
|
+
return parser.getOSName(true) === "android" && osMajorVersion >= 3;
|
|
2293
|
+
},
|
|
2294
|
+
describe() {
|
|
2295
|
+
return {
|
|
2296
|
+
type: PLATFORMS_MAP.tablet
|
|
2297
|
+
};
|
|
2298
|
+
}
|
|
2299
|
+
},
|
|
2300
|
+
{
|
|
2301
|
+
test(parser) {
|
|
2302
|
+
return parser.getOSName(true) === "android";
|
|
2303
|
+
},
|
|
2304
|
+
describe() {
|
|
2305
|
+
return {
|
|
2306
|
+
type: PLATFORMS_MAP.mobile
|
|
2307
|
+
};
|
|
2308
|
+
}
|
|
2309
|
+
},
|
|
2310
|
+
{
|
|
2311
|
+
test(parser) {
|
|
2312
|
+
return parser.getOSName(true) === "macos";
|
|
2313
|
+
},
|
|
2314
|
+
describe() {
|
|
2315
|
+
return {
|
|
2316
|
+
type: PLATFORMS_MAP.desktop,
|
|
2317
|
+
vendor: "Apple"
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
},
|
|
2321
|
+
{
|
|
2322
|
+
test(parser) {
|
|
2323
|
+
return parser.getOSName(true) === "windows";
|
|
2324
|
+
},
|
|
2325
|
+
describe() {
|
|
2326
|
+
return {
|
|
2327
|
+
type: PLATFORMS_MAP.desktop
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
},
|
|
2331
|
+
{
|
|
2332
|
+
test(parser) {
|
|
2333
|
+
return parser.getOSName(true) === "linux";
|
|
2334
|
+
},
|
|
2335
|
+
describe() {
|
|
2336
|
+
return {
|
|
2337
|
+
type: PLATFORMS_MAP.desktop
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
},
|
|
2341
|
+
{
|
|
2342
|
+
test(parser) {
|
|
2343
|
+
return parser.getOSName(true) === "playstation 4";
|
|
2344
|
+
},
|
|
2345
|
+
describe() {
|
|
2346
|
+
return {
|
|
2347
|
+
type: PLATFORMS_MAP.tv
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
},
|
|
2351
|
+
{
|
|
2352
|
+
test(parser) {
|
|
2353
|
+
return parser.getOSName(true) === "roku";
|
|
2354
|
+
},
|
|
2355
|
+
describe() {
|
|
2356
|
+
return {
|
|
2357
|
+
type: PLATFORMS_MAP.tv
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
];
|
|
2362
|
+
var enginesParsersList = [
|
|
2363
|
+
{
|
|
2364
|
+
test(parser) {
|
|
2365
|
+
return parser.getBrowserName(true) === "microsoft edge";
|
|
2366
|
+
},
|
|
2367
|
+
describe(ua) {
|
|
2368
|
+
const isBlinkBased = /\sedg\//i.test(ua);
|
|
2369
|
+
if (isBlinkBased) {
|
|
2370
|
+
return {
|
|
2371
|
+
name: ENGINE_MAP.Blink
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
const version = Utils.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i, ua);
|
|
2375
|
+
return {
|
|
2376
|
+
name: ENGINE_MAP.EdgeHTML,
|
|
2377
|
+
version
|
|
2378
|
+
};
|
|
2379
|
+
}
|
|
2380
|
+
},
|
|
2381
|
+
{
|
|
2382
|
+
test: [/trident/i],
|
|
2383
|
+
describe(ua) {
|
|
2384
|
+
const engine = {
|
|
2385
|
+
name: ENGINE_MAP.Trident
|
|
2386
|
+
};
|
|
2387
|
+
const version = Utils.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i, ua);
|
|
2388
|
+
if (version) {
|
|
2389
|
+
engine.version = version;
|
|
2390
|
+
}
|
|
2391
|
+
return engine;
|
|
2392
|
+
}
|
|
2393
|
+
},
|
|
2394
|
+
{
|
|
2395
|
+
test(parser) {
|
|
2396
|
+
return parser.test(/presto/i);
|
|
2397
|
+
},
|
|
2398
|
+
describe(ua) {
|
|
2399
|
+
const engine = {
|
|
2400
|
+
name: ENGINE_MAP.Presto
|
|
2401
|
+
};
|
|
2402
|
+
const version = Utils.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i, ua);
|
|
2403
|
+
if (version) {
|
|
2404
|
+
engine.version = version;
|
|
2405
|
+
}
|
|
2406
|
+
return engine;
|
|
2407
|
+
}
|
|
2408
|
+
},
|
|
2409
|
+
{
|
|
2410
|
+
test(parser) {
|
|
2411
|
+
const isGecko = parser.test(/gecko/i);
|
|
2412
|
+
const likeGecko = parser.test(/like gecko/i);
|
|
2413
|
+
return isGecko && !likeGecko;
|
|
2414
|
+
},
|
|
2415
|
+
describe(ua) {
|
|
2416
|
+
const engine = {
|
|
2417
|
+
name: ENGINE_MAP.Gecko
|
|
2418
|
+
};
|
|
2419
|
+
const version = Utils.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i, ua);
|
|
2420
|
+
if (version) {
|
|
2421
|
+
engine.version = version;
|
|
2422
|
+
}
|
|
2423
|
+
return engine;
|
|
2424
|
+
}
|
|
2425
|
+
},
|
|
2426
|
+
{
|
|
2427
|
+
test: [/(apple)?webkit\/537\.36/i],
|
|
2428
|
+
describe() {
|
|
2429
|
+
return {
|
|
2430
|
+
name: ENGINE_MAP.Blink
|
|
2431
|
+
};
|
|
2432
|
+
}
|
|
2433
|
+
},
|
|
2434
|
+
{
|
|
2435
|
+
test: [/(apple)?webkit/i],
|
|
2436
|
+
describe(ua) {
|
|
2437
|
+
const engine = {
|
|
2438
|
+
name: ENGINE_MAP.WebKit
|
|
2439
|
+
};
|
|
2440
|
+
const version = Utils.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i, ua);
|
|
2441
|
+
if (version) {
|
|
2442
|
+
engine.version = version;
|
|
2443
|
+
}
|
|
2444
|
+
return engine;
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
];
|
|
2448
|
+
class Parser {
|
|
2449
|
+
constructor(UA, skipParsing = false) {
|
|
2450
|
+
if (UA === void 0 || UA === null || UA === "") {
|
|
2451
|
+
throw new Error("UserAgent parameter can't be empty");
|
|
2452
|
+
}
|
|
2453
|
+
this._ua = UA;
|
|
2454
|
+
this.parsedResult = {};
|
|
2455
|
+
if (skipParsing !== true) {
|
|
2456
|
+
this.parse();
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2459
|
+
getUA() {
|
|
2460
|
+
return this._ua;
|
|
2461
|
+
}
|
|
2462
|
+
test(regex) {
|
|
2463
|
+
return regex.test(this._ua);
|
|
2464
|
+
}
|
|
2465
|
+
parseBrowser() {
|
|
2466
|
+
this.parsedResult.browser = {};
|
|
2467
|
+
const browserDescriptor = Utils.find(browsersList, (_browser) => {
|
|
2468
|
+
if (typeof _browser.test === "function") {
|
|
2469
|
+
return _browser.test(this);
|
|
2470
|
+
}
|
|
2471
|
+
if (_browser.test instanceof Array) {
|
|
2472
|
+
return _browser.test.some((condition) => this.test(condition));
|
|
2473
|
+
}
|
|
2474
|
+
throw new Error("Browser's test function is not valid");
|
|
2475
|
+
});
|
|
2476
|
+
if (browserDescriptor) {
|
|
2477
|
+
this.parsedResult.browser = browserDescriptor.describe(this.getUA());
|
|
2478
|
+
}
|
|
2479
|
+
return this.parsedResult.browser;
|
|
2480
|
+
}
|
|
2481
|
+
getBrowser() {
|
|
2482
|
+
if (this.parsedResult.browser) {
|
|
2483
|
+
return this.parsedResult.browser;
|
|
2484
|
+
}
|
|
2485
|
+
return this.parseBrowser();
|
|
2486
|
+
}
|
|
2487
|
+
getBrowserName(toLowerCase) {
|
|
2488
|
+
if (toLowerCase) {
|
|
2489
|
+
return String(this.getBrowser().name).toLowerCase() || "";
|
|
2490
|
+
}
|
|
2491
|
+
return this.getBrowser().name || "";
|
|
2492
|
+
}
|
|
2493
|
+
getBrowserVersion() {
|
|
2494
|
+
return this.getBrowser().version;
|
|
2495
|
+
}
|
|
2496
|
+
getOS() {
|
|
2497
|
+
if (this.parsedResult.os) {
|
|
2498
|
+
return this.parsedResult.os;
|
|
2499
|
+
}
|
|
2500
|
+
return this.parseOS();
|
|
2501
|
+
}
|
|
2502
|
+
parseOS() {
|
|
2503
|
+
this.parsedResult.os = {};
|
|
2504
|
+
const os = Utils.find(osParsersList, (_os) => {
|
|
2505
|
+
if (typeof _os.test === "function") {
|
|
2506
|
+
return _os.test(this);
|
|
2507
|
+
}
|
|
2508
|
+
if (_os.test instanceof Array) {
|
|
2509
|
+
return _os.test.some((condition) => this.test(condition));
|
|
2510
|
+
}
|
|
2511
|
+
throw new Error("Browser's test function is not valid");
|
|
2512
|
+
});
|
|
2513
|
+
if (os) {
|
|
2514
|
+
this.parsedResult.os = os.describe(this.getUA());
|
|
2515
|
+
}
|
|
2516
|
+
return this.parsedResult.os;
|
|
2517
|
+
}
|
|
2518
|
+
getOSName(toLowerCase) {
|
|
2519
|
+
const { name } = this.getOS();
|
|
2520
|
+
if (toLowerCase) {
|
|
2521
|
+
return String(name).toLowerCase() || "";
|
|
2522
|
+
}
|
|
2523
|
+
return name || "";
|
|
2524
|
+
}
|
|
2525
|
+
getOSVersion() {
|
|
2526
|
+
return this.getOS().version;
|
|
2527
|
+
}
|
|
2528
|
+
getPlatform() {
|
|
2529
|
+
if (this.parsedResult.platform) {
|
|
2530
|
+
return this.parsedResult.platform;
|
|
2531
|
+
}
|
|
2532
|
+
return this.parsePlatform();
|
|
2533
|
+
}
|
|
2534
|
+
getPlatformType(toLowerCase = false) {
|
|
2535
|
+
const { type } = this.getPlatform();
|
|
2536
|
+
if (toLowerCase) {
|
|
2537
|
+
return String(type).toLowerCase() || "";
|
|
2538
|
+
}
|
|
2539
|
+
return type || "";
|
|
2540
|
+
}
|
|
2541
|
+
parsePlatform() {
|
|
2542
|
+
this.parsedResult.platform = {};
|
|
2543
|
+
const platform = Utils.find(platformParsersList, (_platform) => {
|
|
2544
|
+
if (typeof _platform.test === "function") {
|
|
2545
|
+
return _platform.test(this);
|
|
2546
|
+
}
|
|
2547
|
+
if (_platform.test instanceof Array) {
|
|
2548
|
+
return _platform.test.some((condition) => this.test(condition));
|
|
2549
|
+
}
|
|
2550
|
+
throw new Error("Browser's test function is not valid");
|
|
2551
|
+
});
|
|
2552
|
+
if (platform) {
|
|
2553
|
+
this.parsedResult.platform = platform.describe(this.getUA());
|
|
2554
|
+
}
|
|
2555
|
+
return this.parsedResult.platform;
|
|
2556
|
+
}
|
|
2557
|
+
getEngine() {
|
|
2558
|
+
if (this.parsedResult.engine) {
|
|
2559
|
+
return this.parsedResult.engine;
|
|
2560
|
+
}
|
|
2561
|
+
return this.parseEngine();
|
|
2562
|
+
}
|
|
2563
|
+
getEngineName(toLowerCase) {
|
|
2564
|
+
if (toLowerCase) {
|
|
2565
|
+
return String(this.getEngine().name).toLowerCase() || "";
|
|
2566
|
+
}
|
|
2567
|
+
return this.getEngine().name || "";
|
|
2568
|
+
}
|
|
2569
|
+
parseEngine() {
|
|
2570
|
+
this.parsedResult.engine = {};
|
|
2571
|
+
const engine = Utils.find(enginesParsersList, (_engine) => {
|
|
2572
|
+
if (typeof _engine.test === "function") {
|
|
2573
|
+
return _engine.test(this);
|
|
2574
|
+
}
|
|
2575
|
+
if (_engine.test instanceof Array) {
|
|
2576
|
+
return _engine.test.some((condition) => this.test(condition));
|
|
2577
|
+
}
|
|
2578
|
+
throw new Error("Browser's test function is not valid");
|
|
2579
|
+
});
|
|
2580
|
+
if (engine) {
|
|
2581
|
+
this.parsedResult.engine = engine.describe(this.getUA());
|
|
2582
|
+
}
|
|
2583
|
+
return this.parsedResult.engine;
|
|
2584
|
+
}
|
|
2585
|
+
parse() {
|
|
2586
|
+
this.parseBrowser();
|
|
2587
|
+
this.parseOS();
|
|
2588
|
+
this.parsePlatform();
|
|
2589
|
+
this.parseEngine();
|
|
2590
|
+
return this;
|
|
2591
|
+
}
|
|
2592
|
+
getResult() {
|
|
2593
|
+
return Utils.assign({}, this.parsedResult);
|
|
2594
|
+
}
|
|
2595
|
+
satisfies(checkTree) {
|
|
2596
|
+
const platformsAndOSes = {};
|
|
2597
|
+
let platformsAndOSCounter = 0;
|
|
2598
|
+
const browsers = {};
|
|
2599
|
+
let browsersCounter = 0;
|
|
2600
|
+
const allDefinitions = Object.keys(checkTree);
|
|
2601
|
+
allDefinitions.forEach((key) => {
|
|
2602
|
+
const currentDefinition = checkTree[key];
|
|
2603
|
+
if (typeof currentDefinition === "string") {
|
|
2604
|
+
browsers[key] = currentDefinition;
|
|
2605
|
+
browsersCounter += 1;
|
|
2606
|
+
} else if (typeof currentDefinition === "object") {
|
|
2607
|
+
platformsAndOSes[key] = currentDefinition;
|
|
2608
|
+
platformsAndOSCounter += 1;
|
|
2609
|
+
}
|
|
2610
|
+
});
|
|
2611
|
+
if (platformsAndOSCounter > 0) {
|
|
2612
|
+
const platformsAndOSNames = Object.keys(platformsAndOSes);
|
|
2613
|
+
const OSMatchingDefinition = Utils.find(platformsAndOSNames, (name) => this.isOS(name));
|
|
2614
|
+
if (OSMatchingDefinition) {
|
|
2615
|
+
const osResult = this.satisfies(platformsAndOSes[OSMatchingDefinition]);
|
|
2616
|
+
if (osResult !== void 0) {
|
|
2617
|
+
return osResult;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
const platformMatchingDefinition = Utils.find(
|
|
2621
|
+
platformsAndOSNames,
|
|
2622
|
+
(name) => this.isPlatform(name)
|
|
2623
|
+
);
|
|
2624
|
+
if (platformMatchingDefinition) {
|
|
2625
|
+
const platformResult = this.satisfies(platformsAndOSes[platformMatchingDefinition]);
|
|
2626
|
+
if (platformResult !== void 0) {
|
|
2627
|
+
return platformResult;
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
if (browsersCounter > 0) {
|
|
2632
|
+
const browserNames = Object.keys(browsers);
|
|
2633
|
+
const matchingDefinition = Utils.find(browserNames, (name) => this.isBrowser(name, true));
|
|
2634
|
+
if (matchingDefinition !== void 0) {
|
|
2635
|
+
return this.compareVersion(browsers[matchingDefinition]);
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
return void 0;
|
|
2639
|
+
}
|
|
2640
|
+
isBrowser(browserName, includingAlias = false) {
|
|
2641
|
+
const defaultBrowserName = this.getBrowserName().toLowerCase();
|
|
2642
|
+
let browserNameLower = browserName.toLowerCase();
|
|
2643
|
+
const alias = Utils.getBrowserTypeByAlias(browserNameLower);
|
|
2644
|
+
if (includingAlias && alias) {
|
|
2645
|
+
browserNameLower = alias.toLowerCase();
|
|
2646
|
+
}
|
|
2647
|
+
return browserNameLower === defaultBrowserName;
|
|
2648
|
+
}
|
|
2649
|
+
compareVersion(version) {
|
|
2650
|
+
let expectedResults = [0];
|
|
2651
|
+
let comparableVersion = version;
|
|
2652
|
+
let isLoose = false;
|
|
2653
|
+
const currentBrowserVersion = this.getBrowserVersion();
|
|
2654
|
+
if (typeof currentBrowserVersion !== "string") {
|
|
2655
|
+
return void 0;
|
|
2656
|
+
}
|
|
2657
|
+
if (version[0] === ">" || version[0] === "<") {
|
|
2658
|
+
comparableVersion = version.substr(1);
|
|
2659
|
+
if (version[1] === "=") {
|
|
2660
|
+
isLoose = true;
|
|
2661
|
+
comparableVersion = version.substr(2);
|
|
2662
|
+
} else {
|
|
2663
|
+
expectedResults = [];
|
|
2664
|
+
}
|
|
2665
|
+
if (version[0] === ">") {
|
|
2666
|
+
expectedResults.push(1);
|
|
2667
|
+
} else {
|
|
2668
|
+
expectedResults.push(-1);
|
|
2669
|
+
}
|
|
2670
|
+
} else if (version[0] === "=") {
|
|
2671
|
+
comparableVersion = version.substr(1);
|
|
2672
|
+
} else if (version[0] === "~") {
|
|
2673
|
+
isLoose = true;
|
|
2674
|
+
comparableVersion = version.substr(1);
|
|
2675
|
+
}
|
|
2676
|
+
return expectedResults.indexOf(
|
|
2677
|
+
Utils.compareVersions(currentBrowserVersion, comparableVersion, isLoose)
|
|
2678
|
+
) > -1;
|
|
2679
|
+
}
|
|
2680
|
+
isOS(osName) {
|
|
2681
|
+
return this.getOSName(true) === String(osName).toLowerCase();
|
|
2682
|
+
}
|
|
2683
|
+
isPlatform(platformType) {
|
|
2684
|
+
return this.getPlatformType(true) === String(platformType).toLowerCase();
|
|
2685
|
+
}
|
|
2686
|
+
isEngine(engineName) {
|
|
2687
|
+
return this.getEngineName(true) === String(engineName).toLowerCase();
|
|
2688
|
+
}
|
|
2689
|
+
is(anything, includingAlias = false) {
|
|
2690
|
+
return this.isBrowser(anything, includingAlias) || this.isOS(anything) || this.isPlatform(anything);
|
|
2691
|
+
}
|
|
2692
|
+
some(anythings = []) {
|
|
2693
|
+
return anythings.some((anything) => this.is(anything));
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
/*!
|
|
2697
|
+
* Bowser - a browser detector
|
|
2698
|
+
* https://github.com/lancedikson/bowser
|
|
2699
|
+
* MIT License | (c) Dustin Diaz 2012-2015
|
|
2700
|
+
* MIT License | (c) Denis Demchenko 2015-2019
|
|
2701
|
+
*/
|
|
2702
|
+
class Bowser {
|
|
2703
|
+
static getParser(UA, skipParsing = false) {
|
|
2704
|
+
if (typeof UA !== "string") {
|
|
2705
|
+
throw new Error("UserAgent should be a string");
|
|
2706
|
+
}
|
|
2707
|
+
return new Parser(UA, skipParsing);
|
|
2708
|
+
}
|
|
2709
|
+
static parse(UA) {
|
|
2710
|
+
return new Parser(UA).getResult();
|
|
2711
|
+
}
|
|
2712
|
+
static get BROWSER_MAP() {
|
|
2713
|
+
return BROWSER_MAP;
|
|
2714
|
+
}
|
|
2715
|
+
static get ENGINE_MAP() {
|
|
2716
|
+
return ENGINE_MAP;
|
|
2717
|
+
}
|
|
2718
|
+
static get OS_MAP() {
|
|
2719
|
+
return OS_MAP;
|
|
2720
|
+
}
|
|
2721
|
+
static get PLATFORMS_MAP() {
|
|
2722
|
+
return PLATFORMS_MAP;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
function getBrowser() {
|
|
2726
|
+
return Bowser.getParser(window.navigator.userAgent);
|
|
2727
|
+
}
|
|
2728
|
+
function buildCanvas2dPipeline(sourcePlayback, backgroundConfig, segmentationConfig, canvas, tflite, WorkerTimers) {
|
|
2729
|
+
const ctx = canvas.getContext("2d");
|
|
2730
|
+
const [segmentationWidth, segmentationHeight] = inputResolutions[segmentationConfig.inputResolution];
|
|
2731
|
+
const segmentationPixelCount = segmentationWidth * segmentationHeight;
|
|
2732
|
+
const segmentationMask = new ImageData(segmentationWidth, segmentationHeight);
|
|
2733
|
+
const segmentationMaskCanvas = document.createElement("canvas");
|
|
2734
|
+
segmentationMaskCanvas.width = segmentationWidth;
|
|
2735
|
+
segmentationMaskCanvas.height = segmentationHeight;
|
|
2736
|
+
const segmentationMaskCtx = segmentationMaskCanvas.getContext("2d", { willReadFrequently: true });
|
|
2737
|
+
const inputMemoryOffset = tflite._getInputMemoryOffset() / 4;
|
|
2738
|
+
const outputMemoryOffset = tflite._getOutputMemoryOffset() / 4;
|
|
2739
|
+
let postProcessingConfig;
|
|
2740
|
+
let currentFrame = null;
|
|
2741
|
+
const blurredBackgroundImagePromise = loadImage("https://assets.dyte.io/backgrounds/blur.jpg");
|
|
2742
|
+
async function render() {
|
|
2743
|
+
currentFrame = await createImageFromVideoElement(sourcePlayback.htmlElement);
|
|
2744
|
+
if (backgroundConfig.type !== "none") {
|
|
2745
|
+
resizeSource();
|
|
2746
|
+
}
|
|
2747
|
+
if (backgroundConfig.type !== "none") {
|
|
2748
|
+
runTFLiteInference();
|
|
2749
|
+
}
|
|
2750
|
+
await runPostProcessing();
|
|
2751
|
+
}
|
|
2752
|
+
function updatePostProcessingConfig(newPostProcessingConfig) {
|
|
2753
|
+
postProcessingConfig = newPostProcessingConfig;
|
|
2754
|
+
}
|
|
2755
|
+
function cleanUp() {
|
|
2756
|
+
}
|
|
2757
|
+
function resizeSource() {
|
|
2758
|
+
segmentationMaskCtx.drawImage(
|
|
2759
|
+
currentFrame,
|
|
2760
|
+
0,
|
|
2761
|
+
0,
|
|
2762
|
+
sourcePlayback.width,
|
|
2763
|
+
sourcePlayback.height,
|
|
2764
|
+
0,
|
|
2765
|
+
0,
|
|
2766
|
+
segmentationWidth,
|
|
2767
|
+
segmentationHeight
|
|
2768
|
+
);
|
|
2769
|
+
if (segmentationConfig.model === "meet" || segmentationConfig.model === "mlkit") {
|
|
2770
|
+
const imageData = segmentationMaskCtx.getImageData(
|
|
2771
|
+
0,
|
|
2772
|
+
0,
|
|
2773
|
+
segmentationWidth,
|
|
2774
|
+
segmentationHeight
|
|
2775
|
+
);
|
|
2776
|
+
for (let i = 0; i < segmentationPixelCount; i++) {
|
|
2777
|
+
tflite.HEAPF32[inputMemoryOffset + i * 3] = imageData.data[i * 4] / 255;
|
|
2778
|
+
tflite.HEAPF32[inputMemoryOffset + i * 3 + 1] = imageData.data[i * 4 + 1] / 255;
|
|
2779
|
+
tflite.HEAPF32[inputMemoryOffset + i * 3 + 2] = imageData.data[i * 4 + 2] / 255;
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
function runTFLiteInference() {
|
|
2784
|
+
tflite._runInference();
|
|
2785
|
+
for (let i = 0; i < segmentationPixelCount; i++) {
|
|
2786
|
+
if (segmentationConfig.model === "meet") {
|
|
2787
|
+
const background = tflite.HEAPF32[outputMemoryOffset + i * 2];
|
|
2788
|
+
const person = tflite.HEAPF32[outputMemoryOffset + i * 2 + 1];
|
|
2789
|
+
const shift = Math.max(background, person);
|
|
2790
|
+
const backgroundExp = Math.exp(background - shift);
|
|
2791
|
+
const personExp = Math.exp(person - shift);
|
|
2792
|
+
segmentationMask.data[i * 4 + 3] = 255 * personExp / (backgroundExp + personExp);
|
|
2793
|
+
} else if (segmentationConfig.model === "mlkit") {
|
|
2794
|
+
const person = tflite.HEAPF32[outputMemoryOffset + i];
|
|
2795
|
+
segmentationMask.data[i * 4 + 3] = 255 * person;
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
segmentationMaskCtx.putImageData(segmentationMask, 0, 0);
|
|
2799
|
+
}
|
|
2800
|
+
async function runPostProcessing() {
|
|
2801
|
+
ctx.globalCompositeOperation = "copy";
|
|
2802
|
+
ctx.filter = "none";
|
|
2803
|
+
ctx.drawImage(currentFrame, 0, 0);
|
|
2804
|
+
if (postProcessingConfig == null ? void 0 : postProcessingConfig.smoothSegmentationMask) {
|
|
2805
|
+
if (backgroundConfig.type === "blur") {
|
|
2806
|
+
ctx.filter = "blur(8px)";
|
|
2807
|
+
} else if (backgroundConfig.type === "image") {
|
|
2808
|
+
ctx.filter = "blur(4px)";
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
if (backgroundConfig.type !== "none") {
|
|
2812
|
+
ctx.globalCompositeOperation = "destination-in";
|
|
2813
|
+
ctx.filter = "none";
|
|
2814
|
+
drawSegmentationMask();
|
|
2815
|
+
}
|
|
2816
|
+
if (backgroundConfig.type === "blur") {
|
|
2817
|
+
await blurBackground();
|
|
2818
|
+
} else {
|
|
2819
|
+
drawBackgroundImage();
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
function drawBackgroundImage() {
|
|
2823
|
+
ctx.globalCompositeOperation = "destination-over";
|
|
2824
|
+
ctx.drawImage(backgroundConfig.backgroundImage, 0, 0);
|
|
2825
|
+
}
|
|
2826
|
+
function drawSegmentationMask() {
|
|
2827
|
+
ctx.drawImage(
|
|
2828
|
+
segmentationMaskCanvas,
|
|
2829
|
+
0,
|
|
2830
|
+
0,
|
|
2831
|
+
segmentationWidth,
|
|
2832
|
+
segmentationHeight,
|
|
2833
|
+
0,
|
|
2834
|
+
0,
|
|
2835
|
+
sourcePlayback.width,
|
|
2836
|
+
sourcePlayback.height
|
|
2837
|
+
);
|
|
2838
|
+
}
|
|
2839
|
+
async function blurBackground() {
|
|
2840
|
+
ctx.globalCompositeOperation = "destination-over";
|
|
2841
|
+
if (getBrowser().getBrowserName() === "Safari") {
|
|
2842
|
+
const blurrredImageBackground = await blurredBackgroundImagePromise;
|
|
2843
|
+
ctx.drawImage(blurrredImageBackground, 0, 0);
|
|
2844
|
+
} else {
|
|
2845
|
+
ctx.filter = `blur(${backgroundConfig.blurLength}px)`;
|
|
2846
|
+
ctx.drawImage(currentFrame, 0, 0);
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
return { render, updatePostProcessingConfig, cleanUp };
|
|
2850
|
+
}
|
|
2851
|
+
const _ImageBackgroundTransformer = class extends BackgroundTransformer {
|
|
2852
|
+
constructor(initParams) {
|
|
2853
|
+
super();
|
|
2854
|
+
__privateAdd(this, _initParams, void 0);
|
|
2855
|
+
__privateAdd(this, _activeRunId, void 0);
|
|
2856
|
+
__privateSet(this, _initParams, initParams);
|
|
2857
|
+
}
|
|
2858
|
+
static async init(initParams) {
|
|
2859
|
+
return new _ImageBackgroundTransformer(initParams);
|
|
2860
|
+
}
|
|
2861
|
+
async createStaticBackgroundImageVideoMiddleware(backgroundImageUrl) {
|
|
2862
|
+
const backgroundImage = await loadImage(backgroundImageUrl);
|
|
2863
|
+
return async ({ canvas, WorkerTimers }) => {
|
|
2864
|
+
const currentRunId = `RUN_${Date.now()}_${Math.round(Math.random() * 100)}`;
|
|
2865
|
+
__privateSet(this, _activeRunId, currentRunId);
|
|
2866
|
+
const rawVideoElement = await this.createCameraVideoElement(
|
|
2867
|
+
__privateGet(this, _initParams).meeting.self.rawVideoTrack
|
|
2868
|
+
);
|
|
2869
|
+
canvas.width = rawVideoElement.width;
|
|
2870
|
+
canvas.height = rawVideoElement.height;
|
|
2871
|
+
const pipelineFn = __privateGet(this, _initParams).segmentationConfig.pipeline === "canvas2dCpu" ? buildCanvas2dPipeline : buildWebGL2Pipeline;
|
|
2872
|
+
const pipeline = pipelineFn(
|
|
2873
|
+
{
|
|
2874
|
+
htmlElement: rawVideoElement,
|
|
2875
|
+
width: __privateGet(this, _initParams).meeting.self.rawVideoTrack.getSettings().width,
|
|
2876
|
+
height: __privateGet(this, _initParams).meeting.self.rawVideoTrack.getSettings().height
|
|
2877
|
+
},
|
|
2878
|
+
{
|
|
2879
|
+
type: "image",
|
|
2880
|
+
backgroundImage
|
|
2881
|
+
},
|
|
2882
|
+
__privateGet(this, _initParams).segmentationConfig,
|
|
2883
|
+
canvas,
|
|
2884
|
+
__privateGet(this, _initParams).tflite,
|
|
2885
|
+
WorkerTimers
|
|
2886
|
+
);
|
|
2887
|
+
pipeline.updatePostProcessingConfig(__privateGet(this, _initParams).postProcessingConfig);
|
|
2888
|
+
const targetTimerTimeoutMs = 1e3 / __privateGet(this, _initParams).segmentationConfig.targetFps;
|
|
2889
|
+
const render = async () => {
|
|
2890
|
+
if (currentRunId !== __privateGet(this, _activeRunId) || !__privateGet(this, _initParams).meeting.self.videoEnabled) {
|
|
2891
|
+
await pipeline.cleanUp();
|
|
2892
|
+
return;
|
|
2893
|
+
}
|
|
2894
|
+
const startTime = performance.now();
|
|
2895
|
+
await pipeline.render();
|
|
2896
|
+
WorkerTimers.setTimeout(
|
|
2897
|
+
render,
|
|
2898
|
+
Math.max(0, targetTimerTimeoutMs - (performance.now() - startTime))
|
|
2899
|
+
);
|
|
2900
|
+
};
|
|
2901
|
+
WorkerTimers.setTimeout(() => {
|
|
2902
|
+
render();
|
|
2903
|
+
}, 0);
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
destruct() {
|
|
2907
|
+
__privateSet(this, _activeRunId, null);
|
|
2908
|
+
}
|
|
2909
|
+
};
|
|
2910
|
+
let ImageBackgroundTransformer = _ImageBackgroundTransformer;
|
|
2911
|
+
_initParams = new WeakMap();
|
|
2912
|
+
_activeRunId = new WeakMap();
|
|
2913
|
+
const _SimpleBackgroundTransformer = class extends BackgroundTransformer {
|
|
2914
|
+
constructor(initParams) {
|
|
2915
|
+
super();
|
|
2916
|
+
__privateAdd(this, _initParams2, void 0);
|
|
2917
|
+
__privateAdd(this, _activeRunId2, void 0);
|
|
2918
|
+
__privateSet(this, _initParams2, initParams);
|
|
2919
|
+
}
|
|
2920
|
+
static async init(initParams) {
|
|
2921
|
+
return new _SimpleBackgroundTransformer(initParams);
|
|
2922
|
+
}
|
|
2923
|
+
async createBackgroundBlurVideoMiddleware(blurLength) {
|
|
2924
|
+
return async ({ canvas, WorkerTimers }) => {
|
|
2925
|
+
const currentRunId = `RUN_${Date.now()}_${Math.round(Math.random() * 100)}`;
|
|
2926
|
+
__privateSet(this, _activeRunId2, currentRunId);
|
|
2927
|
+
const rawVideoElement = await this.createCameraVideoElement(
|
|
2928
|
+
__privateGet(this, _initParams2).meeting.self.rawVideoTrack
|
|
2929
|
+
);
|
|
2930
|
+
canvas.width = rawVideoElement.width;
|
|
2931
|
+
canvas.height = rawVideoElement.height;
|
|
2932
|
+
const pipelineFn = __privateGet(this, _initParams2).segmentationConfig.pipeline === "canvas2dCpu" ? buildCanvas2dPipeline : buildWebGL2Pipeline;
|
|
2933
|
+
const pipeline = pipelineFn(
|
|
2934
|
+
{
|
|
2935
|
+
htmlElement: rawVideoElement,
|
|
2936
|
+
width: __privateGet(this, _initParams2).meeting.self.rawVideoTrack.getSettings().width,
|
|
2937
|
+
height: __privateGet(this, _initParams2).meeting.self.rawVideoTrack.getSettings().height
|
|
2938
|
+
},
|
|
2939
|
+
{
|
|
2940
|
+
type: "blur",
|
|
2941
|
+
blurLength
|
|
2942
|
+
},
|
|
2943
|
+
__privateGet(this, _initParams2).segmentationConfig,
|
|
2944
|
+
canvas,
|
|
2945
|
+
__privateGet(this, _initParams2).tflite,
|
|
2946
|
+
WorkerTimers
|
|
2947
|
+
);
|
|
2948
|
+
pipeline.updatePostProcessingConfig(__privateGet(this, _initParams2).postProcessingConfig);
|
|
2949
|
+
const targetTimerTimeoutMs = 1e3 / __privateGet(this, _initParams2).segmentationConfig.targetFps;
|
|
2950
|
+
const render = async () => {
|
|
2951
|
+
if (currentRunId !== __privateGet(this, _activeRunId2) || !__privateGet(this, _initParams2).meeting.self.videoEnabled) {
|
|
2952
|
+
await pipeline.cleanUp();
|
|
2953
|
+
return;
|
|
2954
|
+
}
|
|
2955
|
+
const startTime = performance.now();
|
|
2956
|
+
await pipeline.render();
|
|
2957
|
+
WorkerTimers.setTimeout(
|
|
2958
|
+
render,
|
|
2959
|
+
Math.max(0, targetTimerTimeoutMs - (performance.now() - startTime))
|
|
2960
|
+
);
|
|
2961
|
+
};
|
|
2962
|
+
WorkerTimers.setTimeout(() => {
|
|
2963
|
+
render();
|
|
2964
|
+
}, 0);
|
|
2965
|
+
};
|
|
2966
|
+
}
|
|
2967
|
+
async destruct() {
|
|
2968
|
+
__privateSet(this, _activeRunId2, null);
|
|
2969
|
+
}
|
|
2970
|
+
};
|
|
2971
|
+
let SimpleBackgroundTransformer = _SimpleBackgroundTransformer;
|
|
2972
|
+
_initParams2 = new WeakMap();
|
|
2973
|
+
_activeRunId2 = new WeakMap();
|
|
2974
|
+
var createTFLiteModule = (() => {
|
|
2975
|
+
var _scriptDir = "https://assets.dyte.io/virtual-bg/";
|
|
2976
|
+
return function(createTFLiteModule2) {
|
|
2977
|
+
createTFLiteModule2 = createTFLiteModule2 || {};
|
|
2978
|
+
var Module = typeof createTFLiteModule2 != "undefined" ? createTFLiteModule2 : {};
|
|
2979
|
+
var readyPromiseResolve, readyPromiseReject;
|
|
2980
|
+
Module["ready"] = new Promise(function(resolve, reject) {
|
|
2981
|
+
readyPromiseResolve = resolve;
|
|
2982
|
+
readyPromiseReject = reject;
|
|
2983
|
+
});
|
|
2984
|
+
var moduleOverrides = Object.assign({}, Module);
|
|
2985
|
+
var thisProgram = "./this.program";
|
|
2986
|
+
var quit_ = (status, toThrow) => {
|
|
2987
|
+
throw toThrow;
|
|
2988
|
+
};
|
|
2989
|
+
var ENVIRONMENT_IS_WEB = true;
|
|
2990
|
+
var scriptDirectory = "";
|
|
2991
|
+
function locateFile(path) {
|
|
2992
|
+
if (Module["locateFile"]) {
|
|
2993
|
+
return Module["locateFile"](path, scriptDirectory);
|
|
2994
|
+
}
|
|
2995
|
+
return scriptDirectory + path;
|
|
2996
|
+
}
|
|
2997
|
+
var readBinary;
|
|
2998
|
+
{
|
|
2999
|
+
if (typeof document != "undefined" && document.currentScript) {
|
|
3000
|
+
scriptDirectory = document.currentScript.src;
|
|
3001
|
+
}
|
|
3002
|
+
{
|
|
3003
|
+
scriptDirectory = _scriptDir;
|
|
3004
|
+
}
|
|
3005
|
+
if (scriptDirectory.indexOf("blob:") !== 0) {
|
|
3006
|
+
scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1);
|
|
3007
|
+
} else {
|
|
3008
|
+
scriptDirectory = "";
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
var out = Module["print"] || console.log.bind(console);
|
|
3012
|
+
var err = Module["printErr"] || console.warn.bind(console);
|
|
3013
|
+
Object.assign(Module, moduleOverrides);
|
|
3014
|
+
moduleOverrides = null;
|
|
3015
|
+
if (Module["arguments"])
|
|
3016
|
+
Module["arguments"];
|
|
3017
|
+
if (Module["thisProgram"])
|
|
3018
|
+
thisProgram = Module["thisProgram"];
|
|
3019
|
+
if (Module["quit"])
|
|
3020
|
+
quit_ = Module["quit"];
|
|
3021
|
+
var wasmBinary;
|
|
3022
|
+
if (Module["wasmBinary"])
|
|
3023
|
+
wasmBinary = Module["wasmBinary"];
|
|
3024
|
+
var noExitRuntime = Module["noExitRuntime"] || true;
|
|
3025
|
+
if (typeof WebAssembly != "object") {
|
|
3026
|
+
abort("no native wasm support detected");
|
|
3027
|
+
}
|
|
3028
|
+
var wasmMemory;
|
|
3029
|
+
var ABORT = false;
|
|
3030
|
+
var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : void 0;
|
|
3031
|
+
function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {
|
|
3032
|
+
var endIdx = idx + maxBytesToRead;
|
|
3033
|
+
var endPtr = idx;
|
|
3034
|
+
while (heapOrArray[endPtr] && !(endPtr >= endIdx))
|
|
3035
|
+
++endPtr;
|
|
3036
|
+
if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
|
|
3037
|
+
return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
|
|
3038
|
+
}
|
|
3039
|
+
var str = "";
|
|
3040
|
+
while (idx < endPtr) {
|
|
3041
|
+
var u0 = heapOrArray[idx++];
|
|
3042
|
+
if (!(u0 & 128)) {
|
|
3043
|
+
str += String.fromCharCode(u0);
|
|
3044
|
+
continue;
|
|
3045
|
+
}
|
|
3046
|
+
var u1 = heapOrArray[idx++] & 63;
|
|
3047
|
+
if ((u0 & 224) == 192) {
|
|
3048
|
+
str += String.fromCharCode((u0 & 31) << 6 | u1);
|
|
3049
|
+
continue;
|
|
3050
|
+
}
|
|
3051
|
+
var u2 = heapOrArray[idx++] & 63;
|
|
3052
|
+
if ((u0 & 240) == 224) {
|
|
3053
|
+
u0 = (u0 & 15) << 12 | u1 << 6 | u2;
|
|
3054
|
+
} else {
|
|
3055
|
+
u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heapOrArray[idx++] & 63;
|
|
3056
|
+
}
|
|
3057
|
+
if (u0 < 65536) {
|
|
3058
|
+
str += String.fromCharCode(u0);
|
|
3059
|
+
} else {
|
|
3060
|
+
var ch = u0 - 65536;
|
|
3061
|
+
str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023);
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
return str;
|
|
3065
|
+
}
|
|
3066
|
+
var buffer, HEAP8, HEAPU8, HEAPU32;
|
|
3067
|
+
function updateGlobalBufferAndViews(buf) {
|
|
3068
|
+
buffer = buf;
|
|
3069
|
+
Module["HEAP8"] = HEAP8 = new Int8Array(buf);
|
|
3070
|
+
Module["HEAP16"] = new Int16Array(buf);
|
|
3071
|
+
Module["HEAP32"] = new Int32Array(buf);
|
|
3072
|
+
Module["HEAPU8"] = HEAPU8 = new Uint8Array(buf);
|
|
3073
|
+
Module["HEAPU16"] = new Uint16Array(buf);
|
|
3074
|
+
Module["HEAPU32"] = HEAPU32 = new Uint32Array(buf);
|
|
3075
|
+
Module["HEAPF32"] = new Float32Array(buf);
|
|
3076
|
+
Module["HEAPF64"] = new Float64Array(buf);
|
|
3077
|
+
}
|
|
3078
|
+
Module["INITIAL_MEMORY"] || 16777216;
|
|
3079
|
+
var __ATPRERUN__ = [];
|
|
3080
|
+
var __ATINIT__ = [];
|
|
3081
|
+
var __ATPOSTRUN__ = [];
|
|
3082
|
+
function keepRuntimeAlive() {
|
|
3083
|
+
return noExitRuntime;
|
|
3084
|
+
}
|
|
3085
|
+
function preRun() {
|
|
3086
|
+
if (Module["preRun"]) {
|
|
3087
|
+
if (typeof Module["preRun"] == "function")
|
|
3088
|
+
Module["preRun"] = [Module["preRun"]];
|
|
3089
|
+
while (Module["preRun"].length) {
|
|
3090
|
+
addOnPreRun(Module["preRun"].shift());
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
callRuntimeCallbacks(__ATPRERUN__);
|
|
3094
|
+
}
|
|
3095
|
+
function initRuntime() {
|
|
3096
|
+
callRuntimeCallbacks(__ATINIT__);
|
|
3097
|
+
}
|
|
3098
|
+
function postRun() {
|
|
3099
|
+
if (Module["postRun"]) {
|
|
3100
|
+
if (typeof Module["postRun"] == "function")
|
|
3101
|
+
Module["postRun"] = [Module["postRun"]];
|
|
3102
|
+
while (Module["postRun"].length) {
|
|
3103
|
+
addOnPostRun(Module["postRun"].shift());
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
callRuntimeCallbacks(__ATPOSTRUN__);
|
|
3107
|
+
}
|
|
3108
|
+
function addOnPreRun(cb) {
|
|
3109
|
+
__ATPRERUN__.unshift(cb);
|
|
3110
|
+
}
|
|
3111
|
+
function addOnInit(cb) {
|
|
3112
|
+
__ATINIT__.unshift(cb);
|
|
3113
|
+
}
|
|
3114
|
+
function addOnPostRun(cb) {
|
|
3115
|
+
__ATPOSTRUN__.unshift(cb);
|
|
3116
|
+
}
|
|
3117
|
+
var runDependencies = 0;
|
|
3118
|
+
var dependenciesFulfilled = null;
|
|
3119
|
+
function addRunDependency(id) {
|
|
3120
|
+
runDependencies++;
|
|
3121
|
+
if (Module["monitorRunDependencies"]) {
|
|
3122
|
+
Module["monitorRunDependencies"](runDependencies);
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
function removeRunDependency(id) {
|
|
3126
|
+
runDependencies--;
|
|
3127
|
+
if (Module["monitorRunDependencies"]) {
|
|
3128
|
+
Module["monitorRunDependencies"](runDependencies);
|
|
3129
|
+
}
|
|
3130
|
+
if (runDependencies == 0) {
|
|
3131
|
+
if (dependenciesFulfilled) {
|
|
3132
|
+
var callback = dependenciesFulfilled;
|
|
3133
|
+
dependenciesFulfilled = null;
|
|
3134
|
+
callback();
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
function abort(what) {
|
|
3139
|
+
{
|
|
3140
|
+
if (Module["onAbort"]) {
|
|
3141
|
+
Module["onAbort"](what);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
what = "Aborted(" + what + ")";
|
|
3145
|
+
err(what);
|
|
3146
|
+
ABORT = true;
|
|
3147
|
+
what += ". Build with -sASSERTIONS for more info.";
|
|
3148
|
+
var e = new WebAssembly.RuntimeError(what);
|
|
3149
|
+
readyPromiseReject(e);
|
|
3150
|
+
throw e;
|
|
3151
|
+
}
|
|
3152
|
+
var dataURIPrefix = "data:application/octet-stream;base64,";
|
|
3153
|
+
function isDataURI(filename) {
|
|
3154
|
+
return filename.startsWith(dataURIPrefix);
|
|
3155
|
+
}
|
|
3156
|
+
var wasmBinaryFile;
|
|
3157
|
+
wasmBinaryFile = "tflite.wasm";
|
|
3158
|
+
if (!isDataURI(wasmBinaryFile)) {
|
|
3159
|
+
wasmBinaryFile = locateFile(wasmBinaryFile);
|
|
3160
|
+
}
|
|
3161
|
+
function getBinary(file) {
|
|
3162
|
+
try {
|
|
3163
|
+
if (file == wasmBinaryFile && wasmBinary) {
|
|
3164
|
+
return new Uint8Array(wasmBinary);
|
|
3165
|
+
}
|
|
3166
|
+
if (readBinary)
|
|
3167
|
+
;
|
|
3168
|
+
throw "both async and sync fetching of the wasm failed";
|
|
3169
|
+
} catch (err2) {
|
|
3170
|
+
abort(err2);
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
function getBinaryPromise() {
|
|
3174
|
+
if (!wasmBinary && ENVIRONMENT_IS_WEB) {
|
|
3175
|
+
if (typeof fetch == "function") {
|
|
3176
|
+
return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) {
|
|
3177
|
+
if (!response["ok"]) {
|
|
3178
|
+
throw "failed to load wasm binary file at '" + wasmBinaryFile + "'";
|
|
3179
|
+
}
|
|
3180
|
+
return response["arrayBuffer"]();
|
|
3181
|
+
}).catch(function() {
|
|
3182
|
+
return getBinary(wasmBinaryFile);
|
|
3183
|
+
});
|
|
3184
|
+
}
|
|
3185
|
+
}
|
|
3186
|
+
return Promise.resolve().then(function() {
|
|
3187
|
+
return getBinary(wasmBinaryFile);
|
|
3188
|
+
});
|
|
3189
|
+
}
|
|
3190
|
+
function createWasm() {
|
|
3191
|
+
var info = { "env": asmLibraryArg, "wasi_snapshot_preview1": asmLibraryArg };
|
|
3192
|
+
function receiveInstance(instance, module) {
|
|
3193
|
+
var exports2 = instance.exports;
|
|
3194
|
+
Module["asm"] = exports2;
|
|
3195
|
+
wasmMemory = Module["asm"]["memory"];
|
|
3196
|
+
updateGlobalBufferAndViews(wasmMemory.buffer);
|
|
3197
|
+
Module["asm"]["__indirect_function_table"];
|
|
3198
|
+
addOnInit(Module["asm"]["__wasm_call_ctors"]);
|
|
3199
|
+
removeRunDependency();
|
|
3200
|
+
}
|
|
3201
|
+
addRunDependency();
|
|
3202
|
+
function receiveInstantiationResult(result) {
|
|
3203
|
+
receiveInstance(result["instance"]);
|
|
3204
|
+
}
|
|
3205
|
+
function instantiateArrayBuffer(receiver) {
|
|
3206
|
+
return getBinaryPromise().then(function(binary) {
|
|
3207
|
+
return WebAssembly.instantiate(binary, info);
|
|
3208
|
+
}).then(function(instance) {
|
|
3209
|
+
return instance;
|
|
3210
|
+
}).then(receiver, function(reason) {
|
|
3211
|
+
err("failed to asynchronously prepare wasm: " + reason);
|
|
3212
|
+
abort(reason);
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
function instantiateAsync() {
|
|
3216
|
+
if (!wasmBinary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(wasmBinaryFile) && typeof fetch == "function") {
|
|
3217
|
+
return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) {
|
|
3218
|
+
var result = WebAssembly.instantiateStreaming(response, info);
|
|
3219
|
+
return result.then(receiveInstantiationResult, function(reason) {
|
|
3220
|
+
err("wasm streaming compile failed: " + reason);
|
|
3221
|
+
err("falling back to ArrayBuffer instantiation");
|
|
3222
|
+
return instantiateArrayBuffer(receiveInstantiationResult);
|
|
3223
|
+
});
|
|
3224
|
+
});
|
|
3225
|
+
} else {
|
|
3226
|
+
return instantiateArrayBuffer(receiveInstantiationResult);
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
if (Module["instantiateWasm"]) {
|
|
3230
|
+
try {
|
|
3231
|
+
var exports = Module["instantiateWasm"](info, receiveInstance);
|
|
3232
|
+
return exports;
|
|
3233
|
+
} catch (e) {
|
|
3234
|
+
err("Module.instantiateWasm callback failed with error: " + e);
|
|
3235
|
+
readyPromiseReject(e);
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
instantiateAsync().catch(readyPromiseReject);
|
|
3239
|
+
return {};
|
|
3240
|
+
}
|
|
3241
|
+
function ExitStatus(status) {
|
|
3242
|
+
this.name = "ExitStatus";
|
|
3243
|
+
this.message = "Program terminated with exit(" + status + ")";
|
|
3244
|
+
this.status = status;
|
|
3245
|
+
}
|
|
3246
|
+
function callRuntimeCallbacks(callbacks) {
|
|
3247
|
+
while (callbacks.length > 0) {
|
|
3248
|
+
callbacks.shift()(Module);
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
function __dlinit(main_dso_handle) {
|
|
3252
|
+
}
|
|
3253
|
+
var dlopenMissingError = "To use dlopen, you need enable dynamic linking, see https://github.com/emscripten-core/emscripten/wiki/Linking";
|
|
3254
|
+
function __dlopen_js(filename, flag) {
|
|
3255
|
+
abort(dlopenMissingError);
|
|
3256
|
+
}
|
|
3257
|
+
function __dlsym_js(handle, symbol) {
|
|
3258
|
+
abort(dlopenMissingError);
|
|
3259
|
+
}
|
|
3260
|
+
var nowIsMonotonic = true;
|
|
3261
|
+
function __emscripten_get_now_is_monotonic() {
|
|
3262
|
+
return nowIsMonotonic;
|
|
3263
|
+
}
|
|
3264
|
+
function __mmap_js(len, prot, flags, fd, off, allocated) {
|
|
3265
|
+
return -52;
|
|
3266
|
+
}
|
|
3267
|
+
function __munmap_js(addr, len, prot, flags, fd, offset) {
|
|
3268
|
+
}
|
|
3269
|
+
function _abort() {
|
|
3270
|
+
abort("");
|
|
3271
|
+
}
|
|
3272
|
+
function _emscripten_date_now() {
|
|
3273
|
+
return Date.now();
|
|
3274
|
+
}
|
|
3275
|
+
function getHeapMax() {
|
|
3276
|
+
return 2147483648;
|
|
3277
|
+
}
|
|
3278
|
+
function _emscripten_get_heap_max() {
|
|
3279
|
+
return getHeapMax();
|
|
3280
|
+
}
|
|
3281
|
+
var _emscripten_get_now;
|
|
3282
|
+
_emscripten_get_now = () => performance.now();
|
|
3283
|
+
function _emscripten_memcpy_big(dest, src, num) {
|
|
3284
|
+
HEAPU8.copyWithin(dest, src, src + num);
|
|
3285
|
+
}
|
|
3286
|
+
function emscripten_realloc_buffer(size) {
|
|
3287
|
+
try {
|
|
3288
|
+
wasmMemory.grow(size - buffer.byteLength + 65535 >>> 16);
|
|
3289
|
+
updateGlobalBufferAndViews(wasmMemory.buffer);
|
|
3290
|
+
return 1;
|
|
3291
|
+
} catch (e) {
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
function _emscripten_resize_heap(requestedSize) {
|
|
3295
|
+
var oldSize = HEAPU8.length;
|
|
3296
|
+
requestedSize = requestedSize >>> 0;
|
|
3297
|
+
var maxHeapSize = getHeapMax();
|
|
3298
|
+
if (requestedSize > maxHeapSize) {
|
|
3299
|
+
return false;
|
|
3300
|
+
}
|
|
3301
|
+
let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
|
|
3302
|
+
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
|
|
3303
|
+
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
|
|
3304
|
+
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
|
|
3305
|
+
var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
|
|
3306
|
+
var replacement = emscripten_realloc_buffer(newSize);
|
|
3307
|
+
if (replacement) {
|
|
3308
|
+
return true;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
return false;
|
|
3312
|
+
}
|
|
3313
|
+
var ENV = {};
|
|
3314
|
+
function getExecutableName() {
|
|
3315
|
+
return thisProgram || "./this.program";
|
|
3316
|
+
}
|
|
3317
|
+
function getEnvStrings() {
|
|
3318
|
+
if (!getEnvStrings.strings) {
|
|
3319
|
+
var lang = (typeof navigator == "object" && navigator.languages && navigator.languages[0] || "C").replace("-", "_") + ".UTF-8";
|
|
3320
|
+
var env = { "USER": "web_user", "LOGNAME": "web_user", "PATH": "/", "PWD": "/", "HOME": "/home/web_user", "LANG": lang, "_": getExecutableName() };
|
|
3321
|
+
for (var x in ENV) {
|
|
3322
|
+
if (ENV[x] === void 0)
|
|
3323
|
+
delete env[x];
|
|
3324
|
+
else
|
|
3325
|
+
env[x] = ENV[x];
|
|
3326
|
+
}
|
|
3327
|
+
var strings = [];
|
|
3328
|
+
for (var x in env) {
|
|
3329
|
+
strings.push(x + "=" + env[x]);
|
|
3330
|
+
}
|
|
3331
|
+
getEnvStrings.strings = strings;
|
|
3332
|
+
}
|
|
3333
|
+
return getEnvStrings.strings;
|
|
3334
|
+
}
|
|
3335
|
+
function writeAsciiToMemory(str, buffer2, dontAddNull) {
|
|
3336
|
+
for (var i = 0; i < str.length; ++i) {
|
|
3337
|
+
HEAP8[buffer2++ >> 0] = str.charCodeAt(i);
|
|
3338
|
+
}
|
|
3339
|
+
if (!dontAddNull)
|
|
3340
|
+
HEAP8[buffer2 >> 0] = 0;
|
|
3341
|
+
}
|
|
3342
|
+
function _environ_get(__environ, environ_buf) {
|
|
3343
|
+
var bufSize = 0;
|
|
3344
|
+
getEnvStrings().forEach(function(string, i) {
|
|
3345
|
+
var ptr = environ_buf + bufSize;
|
|
3346
|
+
HEAPU32[__environ + i * 4 >> 2] = ptr;
|
|
3347
|
+
writeAsciiToMemory(string, ptr);
|
|
3348
|
+
bufSize += string.length + 1;
|
|
3349
|
+
});
|
|
3350
|
+
return 0;
|
|
3351
|
+
}
|
|
3352
|
+
function _environ_sizes_get(penviron_count, penviron_buf_size) {
|
|
3353
|
+
var strings = getEnvStrings();
|
|
3354
|
+
HEAPU32[penviron_count >> 2] = strings.length;
|
|
3355
|
+
var bufSize = 0;
|
|
3356
|
+
strings.forEach(function(string) {
|
|
3357
|
+
bufSize += string.length + 1;
|
|
3358
|
+
});
|
|
3359
|
+
HEAPU32[penviron_buf_size >> 2] = bufSize;
|
|
3360
|
+
return 0;
|
|
3361
|
+
}
|
|
3362
|
+
function _proc_exit(code) {
|
|
3363
|
+
if (!keepRuntimeAlive()) {
|
|
3364
|
+
if (Module["onExit"])
|
|
3365
|
+
Module["onExit"](code);
|
|
3366
|
+
ABORT = true;
|
|
3367
|
+
}
|
|
3368
|
+
quit_(code, new ExitStatus(code));
|
|
3369
|
+
}
|
|
3370
|
+
function exitJS(status, implicit) {
|
|
3371
|
+
_proc_exit(status);
|
|
3372
|
+
}
|
|
3373
|
+
var _exit = exitJS;
|
|
3374
|
+
function _fd_close(fd) {
|
|
3375
|
+
return 52;
|
|
3376
|
+
}
|
|
3377
|
+
function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {
|
|
3378
|
+
return 70;
|
|
3379
|
+
}
|
|
3380
|
+
var printCharBuffers = [null, [], []];
|
|
3381
|
+
function printChar(stream, curr) {
|
|
3382
|
+
var buffer2 = printCharBuffers[stream];
|
|
3383
|
+
if (curr === 0 || curr === 10) {
|
|
3384
|
+
(stream === 1 ? out : err)(UTF8ArrayToString(buffer2, 0));
|
|
3385
|
+
buffer2.length = 0;
|
|
3386
|
+
} else {
|
|
3387
|
+
buffer2.push(curr);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
function _fd_write(fd, iov, iovcnt, pnum) {
|
|
3391
|
+
var num = 0;
|
|
3392
|
+
for (var i = 0; i < iovcnt; i++) {
|
|
3393
|
+
var ptr = HEAPU32[iov >> 2];
|
|
3394
|
+
var len = HEAPU32[iov + 4 >> 2];
|
|
3395
|
+
iov += 8;
|
|
3396
|
+
for (var j = 0; j < len; j++) {
|
|
3397
|
+
printChar(fd, HEAPU8[ptr + j]);
|
|
3398
|
+
}
|
|
3399
|
+
num += len;
|
|
3400
|
+
}
|
|
3401
|
+
HEAPU32[pnum >> 2] = num;
|
|
3402
|
+
return 0;
|
|
3403
|
+
}
|
|
3404
|
+
function getRandomDevice() {
|
|
3405
|
+
if (typeof crypto == "object" && typeof crypto["getRandomValues"] == "function") {
|
|
3406
|
+
var randomBuffer = new Uint8Array(1);
|
|
3407
|
+
return () => {
|
|
3408
|
+
crypto.getRandomValues(randomBuffer);
|
|
3409
|
+
return randomBuffer[0];
|
|
3410
|
+
};
|
|
3411
|
+
} else
|
|
3412
|
+
return () => abort("randomDevice");
|
|
3413
|
+
}
|
|
3414
|
+
function _getentropy(buffer2, size) {
|
|
3415
|
+
if (!_getentropy.randomDevice) {
|
|
3416
|
+
_getentropy.randomDevice = getRandomDevice();
|
|
3417
|
+
}
|
|
3418
|
+
for (var i = 0; i < size; i++) {
|
|
3419
|
+
HEAP8[buffer2 + i >> 0] = _getentropy.randomDevice();
|
|
3420
|
+
}
|
|
3421
|
+
return 0;
|
|
3422
|
+
}
|
|
3423
|
+
var asmLibraryArg = { "_dlinit": __dlinit, "_dlopen_js": __dlopen_js, "_dlsym_js": __dlsym_js, "_emscripten_get_now_is_monotonic": __emscripten_get_now_is_monotonic, "_mmap_js": __mmap_js, "_munmap_js": __munmap_js, "abort": _abort, "emscripten_date_now": _emscripten_date_now, "emscripten_get_heap_max": _emscripten_get_heap_max, "emscripten_get_now": _emscripten_get_now, "emscripten_memcpy_big": _emscripten_memcpy_big, "emscripten_resize_heap": _emscripten_resize_heap, "environ_get": _environ_get, "environ_sizes_get": _environ_sizes_get, "exit": _exit, "fd_close": _fd_close, "fd_seek": _fd_seek, "fd_write": _fd_write, "getentropy": _getentropy };
|
|
3424
|
+
createWasm();
|
|
3425
|
+
Module["___wasm_call_ctors"] = function() {
|
|
3426
|
+
return (Module["___wasm_call_ctors"] = Module["asm"]["__wasm_call_ctors"]).apply(null, arguments);
|
|
3427
|
+
};
|
|
3428
|
+
Module["_getModelBufferMemoryOffset"] = function() {
|
|
3429
|
+
return (Module["_getModelBufferMemoryOffset"] = Module["asm"]["getModelBufferMemoryOffset"]).apply(null, arguments);
|
|
3430
|
+
};
|
|
3431
|
+
Module["_getInputMemoryOffset"] = function() {
|
|
3432
|
+
return (Module["_getInputMemoryOffset"] = Module["asm"]["getInputMemoryOffset"]).apply(null, arguments);
|
|
3433
|
+
};
|
|
3434
|
+
Module["_getInputHeight"] = function() {
|
|
3435
|
+
return (Module["_getInputHeight"] = Module["asm"]["getInputHeight"]).apply(null, arguments);
|
|
3436
|
+
};
|
|
3437
|
+
Module["_getInputWidth"] = function() {
|
|
3438
|
+
return (Module["_getInputWidth"] = Module["asm"]["getInputWidth"]).apply(null, arguments);
|
|
3439
|
+
};
|
|
3440
|
+
Module["_getInputChannelCount"] = function() {
|
|
3441
|
+
return (Module["_getInputChannelCount"] = Module["asm"]["getInputChannelCount"]).apply(null, arguments);
|
|
3442
|
+
};
|
|
3443
|
+
Module["_getOutputMemoryOffset"] = function() {
|
|
3444
|
+
return (Module["_getOutputMemoryOffset"] = Module["asm"]["getOutputMemoryOffset"]).apply(null, arguments);
|
|
3445
|
+
};
|
|
3446
|
+
Module["_getOutputHeight"] = function() {
|
|
3447
|
+
return (Module["_getOutputHeight"] = Module["asm"]["getOutputHeight"]).apply(null, arguments);
|
|
3448
|
+
};
|
|
3449
|
+
Module["_getOutputWidth"] = function() {
|
|
3450
|
+
return (Module["_getOutputWidth"] = Module["asm"]["getOutputWidth"]).apply(null, arguments);
|
|
3451
|
+
};
|
|
3452
|
+
Module["_getOutputChannelCount"] = function() {
|
|
3453
|
+
return (Module["_getOutputChannelCount"] = Module["asm"]["getOutputChannelCount"]).apply(null, arguments);
|
|
3454
|
+
};
|
|
3455
|
+
Module["_loadModel"] = function() {
|
|
3456
|
+
return (Module["_loadModel"] = Module["asm"]["loadModel"]).apply(null, arguments);
|
|
3457
|
+
};
|
|
3458
|
+
Module["_runInference"] = function() {
|
|
3459
|
+
return (Module["_runInference"] = Module["asm"]["runInference"]).apply(null, arguments);
|
|
3460
|
+
};
|
|
3461
|
+
Module["_malloc"] = function() {
|
|
3462
|
+
return (Module["_malloc"] = Module["asm"]["malloc"]).apply(null, arguments);
|
|
3463
|
+
};
|
|
3464
|
+
Module["___errno_location"] = function() {
|
|
3465
|
+
return (Module["___errno_location"] = Module["asm"]["__errno_location"]).apply(null, arguments);
|
|
3466
|
+
};
|
|
3467
|
+
Module["___dl_seterr"] = function() {
|
|
3468
|
+
return (Module["___dl_seterr"] = Module["asm"]["__dl_seterr"]).apply(null, arguments);
|
|
3469
|
+
};
|
|
3470
|
+
Module["stackSave"] = function() {
|
|
3471
|
+
return (Module["stackSave"] = Module["asm"]["stackSave"]).apply(null, arguments);
|
|
3472
|
+
};
|
|
3473
|
+
Module["stackRestore"] = function() {
|
|
3474
|
+
return (Module["stackRestore"] = Module["asm"]["stackRestore"]).apply(null, arguments);
|
|
3475
|
+
};
|
|
3476
|
+
Module["stackAlloc"] = function() {
|
|
3477
|
+
return (Module["stackAlloc"] = Module["asm"]["stackAlloc"]).apply(null, arguments);
|
|
3478
|
+
};
|
|
3479
|
+
Module["dynCall_jjj"] = function() {
|
|
3480
|
+
return (Module["dynCall_jjj"] = Module["asm"]["dynCall_jjj"]).apply(null, arguments);
|
|
3481
|
+
};
|
|
3482
|
+
Module["dynCall_jiii"] = function() {
|
|
3483
|
+
return (Module["dynCall_jiii"] = Module["asm"]["dynCall_jiii"]).apply(null, arguments);
|
|
3484
|
+
};
|
|
3485
|
+
Module["dynCall_iiiijj"] = function() {
|
|
3486
|
+
return (Module["dynCall_iiiijj"] = Module["asm"]["dynCall_iiiijj"]).apply(null, arguments);
|
|
3487
|
+
};
|
|
3488
|
+
Module["dynCall_viijj"] = function() {
|
|
3489
|
+
return (Module["dynCall_viijj"] = Module["asm"]["dynCall_viijj"]).apply(null, arguments);
|
|
3490
|
+
};
|
|
3491
|
+
Module["dynCall_viiijjj"] = function() {
|
|
3492
|
+
return (Module["dynCall_viiijjj"] = Module["asm"]["dynCall_viiijjj"]).apply(null, arguments);
|
|
3493
|
+
};
|
|
3494
|
+
Module["dynCall_iijjiiii"] = function() {
|
|
3495
|
+
return (Module["dynCall_iijjiiii"] = Module["asm"]["dynCall_iijjiiii"]).apply(null, arguments);
|
|
3496
|
+
};
|
|
3497
|
+
Module["dynCall_jiji"] = function() {
|
|
3498
|
+
return (Module["dynCall_jiji"] = Module["asm"]["dynCall_jiji"]).apply(null, arguments);
|
|
3499
|
+
};
|
|
3500
|
+
var calledRun;
|
|
3501
|
+
dependenciesFulfilled = function runCaller() {
|
|
3502
|
+
if (!calledRun)
|
|
3503
|
+
run();
|
|
3504
|
+
if (!calledRun)
|
|
3505
|
+
dependenciesFulfilled = runCaller;
|
|
3506
|
+
};
|
|
3507
|
+
function run(args) {
|
|
3508
|
+
if (runDependencies > 0) {
|
|
3509
|
+
return;
|
|
3510
|
+
}
|
|
3511
|
+
preRun();
|
|
3512
|
+
if (runDependencies > 0) {
|
|
3513
|
+
return;
|
|
3514
|
+
}
|
|
3515
|
+
function doRun() {
|
|
3516
|
+
if (calledRun)
|
|
3517
|
+
return;
|
|
3518
|
+
calledRun = true;
|
|
3519
|
+
Module["calledRun"] = true;
|
|
3520
|
+
if (ABORT)
|
|
3521
|
+
return;
|
|
3522
|
+
initRuntime();
|
|
3523
|
+
readyPromiseResolve(Module);
|
|
3524
|
+
if (Module["onRuntimeInitialized"])
|
|
3525
|
+
Module["onRuntimeInitialized"]();
|
|
3526
|
+
postRun();
|
|
3527
|
+
}
|
|
3528
|
+
if (Module["setStatus"]) {
|
|
3529
|
+
Module["setStatus"]("Running...");
|
|
3530
|
+
setTimeout(function() {
|
|
3531
|
+
setTimeout(function() {
|
|
3532
|
+
Module["setStatus"]("");
|
|
3533
|
+
}, 1);
|
|
3534
|
+
doRun();
|
|
3535
|
+
}, 1);
|
|
3536
|
+
} else {
|
|
3537
|
+
doRun();
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
if (Module["preInit"]) {
|
|
3541
|
+
if (typeof Module["preInit"] == "function")
|
|
3542
|
+
Module["preInit"] = [Module["preInit"]];
|
|
3543
|
+
while (Module["preInit"].length > 0) {
|
|
3544
|
+
Module["preInit"].pop()();
|
|
3545
|
+
}
|
|
3546
|
+
}
|
|
3547
|
+
run();
|
|
3548
|
+
return createTFLiteModule2.ready;
|
|
3549
|
+
};
|
|
3550
|
+
})();
|
|
3551
|
+
var createTFLiteSIMDModule = (() => {
|
|
3552
|
+
var _scriptDir = "https://assets.dyte.io/virtual-bg/";
|
|
3553
|
+
return function(createTFLiteSIMDModule2) {
|
|
3554
|
+
createTFLiteSIMDModule2 = createTFLiteSIMDModule2 || {};
|
|
3555
|
+
var Module = typeof createTFLiteSIMDModule2 != "undefined" ? createTFLiteSIMDModule2 : {};
|
|
3556
|
+
var readyPromiseResolve, readyPromiseReject;
|
|
3557
|
+
Module["ready"] = new Promise(function(resolve, reject) {
|
|
3558
|
+
readyPromiseResolve = resolve;
|
|
3559
|
+
readyPromiseReject = reject;
|
|
3560
|
+
});
|
|
3561
|
+
var moduleOverrides = Object.assign({}, Module);
|
|
3562
|
+
var thisProgram = "./this.program";
|
|
3563
|
+
var quit_ = (status, toThrow) => {
|
|
3564
|
+
throw toThrow;
|
|
3565
|
+
};
|
|
3566
|
+
var ENVIRONMENT_IS_WEB = true;
|
|
3567
|
+
var scriptDirectory = "";
|
|
3568
|
+
function locateFile(path) {
|
|
3569
|
+
if (Module["locateFile"]) {
|
|
3570
|
+
return Module["locateFile"](path, scriptDirectory);
|
|
3571
|
+
}
|
|
3572
|
+
return scriptDirectory + path;
|
|
3573
|
+
}
|
|
3574
|
+
var readBinary;
|
|
3575
|
+
{
|
|
3576
|
+
if (typeof document != "undefined" && document.currentScript) {
|
|
3577
|
+
scriptDirectory = document.currentScript.src;
|
|
3578
|
+
}
|
|
3579
|
+
{
|
|
3580
|
+
scriptDirectory = _scriptDir;
|
|
3581
|
+
}
|
|
3582
|
+
if (scriptDirectory.indexOf("blob:") !== 0) {
|
|
3583
|
+
scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1);
|
|
3584
|
+
} else {
|
|
3585
|
+
scriptDirectory = "";
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
var out = Module["print"] || console.log.bind(console);
|
|
3589
|
+
var err = Module["printErr"] || console.warn.bind(console);
|
|
3590
|
+
Object.assign(Module, moduleOverrides);
|
|
3591
|
+
moduleOverrides = null;
|
|
3592
|
+
if (Module["arguments"])
|
|
3593
|
+
Module["arguments"];
|
|
3594
|
+
if (Module["thisProgram"])
|
|
3595
|
+
thisProgram = Module["thisProgram"];
|
|
3596
|
+
if (Module["quit"])
|
|
3597
|
+
quit_ = Module["quit"];
|
|
3598
|
+
var wasmBinary;
|
|
3599
|
+
if (Module["wasmBinary"])
|
|
3600
|
+
wasmBinary = Module["wasmBinary"];
|
|
3601
|
+
var noExitRuntime = Module["noExitRuntime"] || true;
|
|
3602
|
+
if (typeof WebAssembly != "object") {
|
|
3603
|
+
abort("no native wasm support detected");
|
|
3604
|
+
}
|
|
3605
|
+
var wasmMemory;
|
|
3606
|
+
var ABORT = false;
|
|
3607
|
+
var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder("utf8") : void 0;
|
|
3608
|
+
function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {
|
|
3609
|
+
var endIdx = idx + maxBytesToRead;
|
|
3610
|
+
var endPtr = idx;
|
|
3611
|
+
while (heapOrArray[endPtr] && !(endPtr >= endIdx))
|
|
3612
|
+
++endPtr;
|
|
3613
|
+
if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
|
|
3614
|
+
return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
|
|
3615
|
+
}
|
|
3616
|
+
var str = "";
|
|
3617
|
+
while (idx < endPtr) {
|
|
3618
|
+
var u0 = heapOrArray[idx++];
|
|
3619
|
+
if (!(u0 & 128)) {
|
|
3620
|
+
str += String.fromCharCode(u0);
|
|
3621
|
+
continue;
|
|
3622
|
+
}
|
|
3623
|
+
var u1 = heapOrArray[idx++] & 63;
|
|
3624
|
+
if ((u0 & 224) == 192) {
|
|
3625
|
+
str += String.fromCharCode((u0 & 31) << 6 | u1);
|
|
3626
|
+
continue;
|
|
3627
|
+
}
|
|
3628
|
+
var u2 = heapOrArray[idx++] & 63;
|
|
3629
|
+
if ((u0 & 240) == 224) {
|
|
3630
|
+
u0 = (u0 & 15) << 12 | u1 << 6 | u2;
|
|
3631
|
+
} else {
|
|
3632
|
+
u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heapOrArray[idx++] & 63;
|
|
3633
|
+
}
|
|
3634
|
+
if (u0 < 65536) {
|
|
3635
|
+
str += String.fromCharCode(u0);
|
|
3636
|
+
} else {
|
|
3637
|
+
var ch = u0 - 65536;
|
|
3638
|
+
str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023);
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
return str;
|
|
3642
|
+
}
|
|
3643
|
+
var buffer, HEAP8, HEAPU8, HEAPU32;
|
|
3644
|
+
function updateGlobalBufferAndViews(buf) {
|
|
3645
|
+
buffer = buf;
|
|
3646
|
+
Module["HEAP8"] = HEAP8 = new Int8Array(buf);
|
|
3647
|
+
Module["HEAP16"] = new Int16Array(buf);
|
|
3648
|
+
Module["HEAP32"] = new Int32Array(buf);
|
|
3649
|
+
Module["HEAPU8"] = HEAPU8 = new Uint8Array(buf);
|
|
3650
|
+
Module["HEAPU16"] = new Uint16Array(buf);
|
|
3651
|
+
Module["HEAPU32"] = HEAPU32 = new Uint32Array(buf);
|
|
3652
|
+
Module["HEAPF32"] = new Float32Array(buf);
|
|
3653
|
+
Module["HEAPF64"] = new Float64Array(buf);
|
|
3654
|
+
}
|
|
3655
|
+
Module["INITIAL_MEMORY"] || 16777216;
|
|
3656
|
+
var __ATPRERUN__ = [];
|
|
3657
|
+
var __ATINIT__ = [];
|
|
3658
|
+
var __ATPOSTRUN__ = [];
|
|
3659
|
+
function keepRuntimeAlive() {
|
|
3660
|
+
return noExitRuntime;
|
|
3661
|
+
}
|
|
3662
|
+
function preRun() {
|
|
3663
|
+
if (Module["preRun"]) {
|
|
3664
|
+
if (typeof Module["preRun"] == "function")
|
|
3665
|
+
Module["preRun"] = [Module["preRun"]];
|
|
3666
|
+
while (Module["preRun"].length) {
|
|
3667
|
+
addOnPreRun(Module["preRun"].shift());
|
|
3668
|
+
}
|
|
3669
|
+
}
|
|
3670
|
+
callRuntimeCallbacks(__ATPRERUN__);
|
|
3671
|
+
}
|
|
3672
|
+
function initRuntime() {
|
|
3673
|
+
callRuntimeCallbacks(__ATINIT__);
|
|
3674
|
+
}
|
|
3675
|
+
function postRun() {
|
|
3676
|
+
if (Module["postRun"]) {
|
|
3677
|
+
if (typeof Module["postRun"] == "function")
|
|
3678
|
+
Module["postRun"] = [Module["postRun"]];
|
|
3679
|
+
while (Module["postRun"].length) {
|
|
3680
|
+
addOnPostRun(Module["postRun"].shift());
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
callRuntimeCallbacks(__ATPOSTRUN__);
|
|
3684
|
+
}
|
|
3685
|
+
function addOnPreRun(cb) {
|
|
3686
|
+
__ATPRERUN__.unshift(cb);
|
|
3687
|
+
}
|
|
3688
|
+
function addOnInit(cb) {
|
|
3689
|
+
__ATINIT__.unshift(cb);
|
|
3690
|
+
}
|
|
3691
|
+
function addOnPostRun(cb) {
|
|
3692
|
+
__ATPOSTRUN__.unshift(cb);
|
|
3693
|
+
}
|
|
3694
|
+
var runDependencies = 0;
|
|
3695
|
+
var dependenciesFulfilled = null;
|
|
3696
|
+
function addRunDependency(id) {
|
|
3697
|
+
runDependencies++;
|
|
3698
|
+
if (Module["monitorRunDependencies"]) {
|
|
3699
|
+
Module["monitorRunDependencies"](runDependencies);
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
function removeRunDependency(id) {
|
|
3703
|
+
runDependencies--;
|
|
3704
|
+
if (Module["monitorRunDependencies"]) {
|
|
3705
|
+
Module["monitorRunDependencies"](runDependencies);
|
|
3706
|
+
}
|
|
3707
|
+
if (runDependencies == 0) {
|
|
3708
|
+
if (dependenciesFulfilled) {
|
|
3709
|
+
var callback = dependenciesFulfilled;
|
|
3710
|
+
dependenciesFulfilled = null;
|
|
3711
|
+
callback();
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
function abort(what) {
|
|
3716
|
+
{
|
|
3717
|
+
if (Module["onAbort"]) {
|
|
3718
|
+
Module["onAbort"](what);
|
|
3719
|
+
}
|
|
3720
|
+
}
|
|
3721
|
+
what = "Aborted(" + what + ")";
|
|
3722
|
+
err(what);
|
|
3723
|
+
ABORT = true;
|
|
3724
|
+
what += ". Build with -sASSERTIONS for more info.";
|
|
3725
|
+
var e = new WebAssembly.RuntimeError(what);
|
|
3726
|
+
readyPromiseReject(e);
|
|
3727
|
+
throw e;
|
|
3728
|
+
}
|
|
3729
|
+
var dataURIPrefix = "data:application/octet-stream;base64,";
|
|
3730
|
+
function isDataURI(filename) {
|
|
3731
|
+
return filename.startsWith(dataURIPrefix);
|
|
3732
|
+
}
|
|
3733
|
+
var wasmBinaryFile;
|
|
3734
|
+
wasmBinaryFile = "tflite-simd.wasm";
|
|
3735
|
+
if (!isDataURI(wasmBinaryFile)) {
|
|
3736
|
+
wasmBinaryFile = locateFile(wasmBinaryFile);
|
|
3737
|
+
}
|
|
3738
|
+
function getBinary(file) {
|
|
3739
|
+
try {
|
|
3740
|
+
if (file == wasmBinaryFile && wasmBinary) {
|
|
3741
|
+
return new Uint8Array(wasmBinary);
|
|
3742
|
+
}
|
|
3743
|
+
if (readBinary)
|
|
3744
|
+
;
|
|
3745
|
+
throw "both async and sync fetching of the wasm failed";
|
|
3746
|
+
} catch (err2) {
|
|
3747
|
+
abort(err2);
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
function getBinaryPromise() {
|
|
3751
|
+
if (!wasmBinary && ENVIRONMENT_IS_WEB) {
|
|
3752
|
+
if (typeof fetch == "function") {
|
|
3753
|
+
return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) {
|
|
3754
|
+
if (!response["ok"]) {
|
|
3755
|
+
throw "failed to load wasm binary file at '" + wasmBinaryFile + "'";
|
|
3756
|
+
}
|
|
3757
|
+
return response["arrayBuffer"]();
|
|
3758
|
+
}).catch(function() {
|
|
3759
|
+
return getBinary(wasmBinaryFile);
|
|
3760
|
+
});
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
return Promise.resolve().then(function() {
|
|
3764
|
+
return getBinary(wasmBinaryFile);
|
|
3765
|
+
});
|
|
3766
|
+
}
|
|
3767
|
+
function createWasm() {
|
|
3768
|
+
var info = { "env": asmLibraryArg, "wasi_snapshot_preview1": asmLibraryArg };
|
|
3769
|
+
function receiveInstance(instance, module) {
|
|
3770
|
+
var exports2 = instance.exports;
|
|
3771
|
+
Module["asm"] = exports2;
|
|
3772
|
+
wasmMemory = Module["asm"]["memory"];
|
|
3773
|
+
updateGlobalBufferAndViews(wasmMemory.buffer);
|
|
3774
|
+
Module["asm"]["__indirect_function_table"];
|
|
3775
|
+
addOnInit(Module["asm"]["__wasm_call_ctors"]);
|
|
3776
|
+
removeRunDependency();
|
|
3777
|
+
}
|
|
3778
|
+
addRunDependency();
|
|
3779
|
+
function receiveInstantiationResult(result) {
|
|
3780
|
+
receiveInstance(result["instance"]);
|
|
3781
|
+
}
|
|
3782
|
+
function instantiateArrayBuffer(receiver) {
|
|
3783
|
+
return getBinaryPromise().then(function(binary) {
|
|
3784
|
+
return WebAssembly.instantiate(binary, info);
|
|
3785
|
+
}).then(function(instance) {
|
|
3786
|
+
return instance;
|
|
3787
|
+
}).then(receiver, function(reason) {
|
|
3788
|
+
err("failed to asynchronously prepare wasm: " + reason);
|
|
3789
|
+
abort(reason);
|
|
3790
|
+
});
|
|
3791
|
+
}
|
|
3792
|
+
function instantiateAsync() {
|
|
3793
|
+
if (!wasmBinary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(wasmBinaryFile) && typeof fetch == "function") {
|
|
3794
|
+
return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) {
|
|
3795
|
+
var result = WebAssembly.instantiateStreaming(response, info);
|
|
3796
|
+
return result.then(receiveInstantiationResult, function(reason) {
|
|
3797
|
+
err("wasm streaming compile failed: " + reason);
|
|
3798
|
+
err("falling back to ArrayBuffer instantiation");
|
|
3799
|
+
return instantiateArrayBuffer(receiveInstantiationResult);
|
|
3800
|
+
});
|
|
3801
|
+
});
|
|
3802
|
+
} else {
|
|
3803
|
+
return instantiateArrayBuffer(receiveInstantiationResult);
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
if (Module["instantiateWasm"]) {
|
|
3807
|
+
try {
|
|
3808
|
+
var exports = Module["instantiateWasm"](info, receiveInstance);
|
|
3809
|
+
return exports;
|
|
3810
|
+
} catch (e) {
|
|
3811
|
+
err("Module.instantiateWasm callback failed with error: " + e);
|
|
3812
|
+
readyPromiseReject(e);
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
instantiateAsync().catch(readyPromiseReject);
|
|
3816
|
+
return {};
|
|
3817
|
+
}
|
|
3818
|
+
function ExitStatus(status) {
|
|
3819
|
+
this.name = "ExitStatus";
|
|
3820
|
+
this.message = "Program terminated with exit(" + status + ")";
|
|
3821
|
+
this.status = status;
|
|
3822
|
+
}
|
|
3823
|
+
function callRuntimeCallbacks(callbacks) {
|
|
3824
|
+
while (callbacks.length > 0) {
|
|
3825
|
+
callbacks.shift()(Module);
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
function __dlinit(main_dso_handle) {
|
|
3829
|
+
}
|
|
3830
|
+
var dlopenMissingError = "To use dlopen, you need enable dynamic linking, see https://github.com/emscripten-core/emscripten/wiki/Linking";
|
|
3831
|
+
function __dlopen_js(filename, flag) {
|
|
3832
|
+
abort(dlopenMissingError);
|
|
3833
|
+
}
|
|
3834
|
+
function __dlsym_js(handle, symbol) {
|
|
3835
|
+
abort(dlopenMissingError);
|
|
3836
|
+
}
|
|
3837
|
+
var nowIsMonotonic = true;
|
|
3838
|
+
function __emscripten_get_now_is_monotonic() {
|
|
3839
|
+
return nowIsMonotonic;
|
|
3840
|
+
}
|
|
3841
|
+
function __mmap_js(len, prot, flags, fd, off, allocated) {
|
|
3842
|
+
return -52;
|
|
3843
|
+
}
|
|
3844
|
+
function __munmap_js(addr, len, prot, flags, fd, offset) {
|
|
3845
|
+
}
|
|
3846
|
+
function _abort() {
|
|
3847
|
+
abort("");
|
|
3848
|
+
}
|
|
3849
|
+
function _emscripten_date_now() {
|
|
3850
|
+
return Date.now();
|
|
3851
|
+
}
|
|
3852
|
+
function getHeapMax() {
|
|
3853
|
+
return 2147483648;
|
|
3854
|
+
}
|
|
3855
|
+
function _emscripten_get_heap_max() {
|
|
3856
|
+
return getHeapMax();
|
|
3857
|
+
}
|
|
3858
|
+
var _emscripten_get_now;
|
|
3859
|
+
_emscripten_get_now = () => performance.now();
|
|
3860
|
+
function _emscripten_memcpy_big(dest, src, num) {
|
|
3861
|
+
HEAPU8.copyWithin(dest, src, src + num);
|
|
3862
|
+
}
|
|
3863
|
+
function emscripten_realloc_buffer(size) {
|
|
3864
|
+
try {
|
|
3865
|
+
wasmMemory.grow(size - buffer.byteLength + 65535 >>> 16);
|
|
3866
|
+
updateGlobalBufferAndViews(wasmMemory.buffer);
|
|
3867
|
+
return 1;
|
|
3868
|
+
} catch (e) {
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
function _emscripten_resize_heap(requestedSize) {
|
|
3872
|
+
var oldSize = HEAPU8.length;
|
|
3873
|
+
requestedSize = requestedSize >>> 0;
|
|
3874
|
+
var maxHeapSize = getHeapMax();
|
|
3875
|
+
if (requestedSize > maxHeapSize) {
|
|
3876
|
+
return false;
|
|
3877
|
+
}
|
|
3878
|
+
let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple;
|
|
3879
|
+
for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
|
|
3880
|
+
var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
|
|
3881
|
+
overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
|
|
3882
|
+
var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536));
|
|
3883
|
+
var replacement = emscripten_realloc_buffer(newSize);
|
|
3884
|
+
if (replacement) {
|
|
3885
|
+
return true;
|
|
3886
|
+
}
|
|
3887
|
+
}
|
|
3888
|
+
return false;
|
|
3889
|
+
}
|
|
3890
|
+
var ENV = {};
|
|
3891
|
+
function getExecutableName() {
|
|
3892
|
+
return thisProgram || "./this.program";
|
|
3893
|
+
}
|
|
3894
|
+
function getEnvStrings() {
|
|
3895
|
+
if (!getEnvStrings.strings) {
|
|
3896
|
+
var lang = (typeof navigator == "object" && navigator.languages && navigator.languages[0] || "C").replace("-", "_") + ".UTF-8";
|
|
3897
|
+
var env = { "USER": "web_user", "LOGNAME": "web_user", "PATH": "/", "PWD": "/", "HOME": "/home/web_user", "LANG": lang, "_": getExecutableName() };
|
|
3898
|
+
for (var x in ENV) {
|
|
3899
|
+
if (ENV[x] === void 0)
|
|
3900
|
+
delete env[x];
|
|
3901
|
+
else
|
|
3902
|
+
env[x] = ENV[x];
|
|
3903
|
+
}
|
|
3904
|
+
var strings = [];
|
|
3905
|
+
for (var x in env) {
|
|
3906
|
+
strings.push(x + "=" + env[x]);
|
|
3907
|
+
}
|
|
3908
|
+
getEnvStrings.strings = strings;
|
|
3909
|
+
}
|
|
3910
|
+
return getEnvStrings.strings;
|
|
3911
|
+
}
|
|
3912
|
+
function writeAsciiToMemory(str, buffer2, dontAddNull) {
|
|
3913
|
+
for (var i = 0; i < str.length; ++i) {
|
|
3914
|
+
HEAP8[buffer2++ >> 0] = str.charCodeAt(i);
|
|
3915
|
+
}
|
|
3916
|
+
if (!dontAddNull)
|
|
3917
|
+
HEAP8[buffer2 >> 0] = 0;
|
|
3918
|
+
}
|
|
3919
|
+
function _environ_get(__environ, environ_buf) {
|
|
3920
|
+
var bufSize = 0;
|
|
3921
|
+
getEnvStrings().forEach(function(string, i) {
|
|
3922
|
+
var ptr = environ_buf + bufSize;
|
|
3923
|
+
HEAPU32[__environ + i * 4 >> 2] = ptr;
|
|
3924
|
+
writeAsciiToMemory(string, ptr);
|
|
3925
|
+
bufSize += string.length + 1;
|
|
3926
|
+
});
|
|
3927
|
+
return 0;
|
|
3928
|
+
}
|
|
3929
|
+
function _environ_sizes_get(penviron_count, penviron_buf_size) {
|
|
3930
|
+
var strings = getEnvStrings();
|
|
3931
|
+
HEAPU32[penviron_count >> 2] = strings.length;
|
|
3932
|
+
var bufSize = 0;
|
|
3933
|
+
strings.forEach(function(string) {
|
|
3934
|
+
bufSize += string.length + 1;
|
|
3935
|
+
});
|
|
3936
|
+
HEAPU32[penviron_buf_size >> 2] = bufSize;
|
|
3937
|
+
return 0;
|
|
3938
|
+
}
|
|
3939
|
+
function _proc_exit(code) {
|
|
3940
|
+
if (!keepRuntimeAlive()) {
|
|
3941
|
+
if (Module["onExit"])
|
|
3942
|
+
Module["onExit"](code);
|
|
3943
|
+
ABORT = true;
|
|
3944
|
+
}
|
|
3945
|
+
quit_(code, new ExitStatus(code));
|
|
3946
|
+
}
|
|
3947
|
+
function exitJS(status, implicit) {
|
|
3948
|
+
_proc_exit(status);
|
|
3949
|
+
}
|
|
3950
|
+
var _exit = exitJS;
|
|
3951
|
+
function _fd_close(fd) {
|
|
3952
|
+
return 52;
|
|
3953
|
+
}
|
|
3954
|
+
function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {
|
|
3955
|
+
return 70;
|
|
3956
|
+
}
|
|
3957
|
+
var printCharBuffers = [null, [], []];
|
|
3958
|
+
function printChar(stream, curr) {
|
|
3959
|
+
var buffer2 = printCharBuffers[stream];
|
|
3960
|
+
if (curr === 0 || curr === 10) {
|
|
3961
|
+
(stream === 1 ? out : err)(UTF8ArrayToString(buffer2, 0));
|
|
3962
|
+
buffer2.length = 0;
|
|
3963
|
+
} else {
|
|
3964
|
+
buffer2.push(curr);
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
function _fd_write(fd, iov, iovcnt, pnum) {
|
|
3968
|
+
var num = 0;
|
|
3969
|
+
for (var i = 0; i < iovcnt; i++) {
|
|
3970
|
+
var ptr = HEAPU32[iov >> 2];
|
|
3971
|
+
var len = HEAPU32[iov + 4 >> 2];
|
|
3972
|
+
iov += 8;
|
|
3973
|
+
for (var j = 0; j < len; j++) {
|
|
3974
|
+
printChar(fd, HEAPU8[ptr + j]);
|
|
3975
|
+
}
|
|
3976
|
+
num += len;
|
|
3977
|
+
}
|
|
3978
|
+
HEAPU32[pnum >> 2] = num;
|
|
3979
|
+
return 0;
|
|
3980
|
+
}
|
|
3981
|
+
function getRandomDevice() {
|
|
3982
|
+
if (typeof crypto == "object" && typeof crypto["getRandomValues"] == "function") {
|
|
3983
|
+
var randomBuffer = new Uint8Array(1);
|
|
3984
|
+
return () => {
|
|
3985
|
+
crypto.getRandomValues(randomBuffer);
|
|
3986
|
+
return randomBuffer[0];
|
|
3987
|
+
};
|
|
3988
|
+
} else
|
|
3989
|
+
return () => abort("randomDevice");
|
|
3990
|
+
}
|
|
3991
|
+
function _getentropy(buffer2, size) {
|
|
3992
|
+
if (!_getentropy.randomDevice) {
|
|
3993
|
+
_getentropy.randomDevice = getRandomDevice();
|
|
3994
|
+
}
|
|
3995
|
+
for (var i = 0; i < size; i++) {
|
|
3996
|
+
HEAP8[buffer2 + i >> 0] = _getentropy.randomDevice();
|
|
3997
|
+
}
|
|
3998
|
+
return 0;
|
|
3999
|
+
}
|
|
4000
|
+
var asmLibraryArg = { "_dlinit": __dlinit, "_dlopen_js": __dlopen_js, "_dlsym_js": __dlsym_js, "_emscripten_get_now_is_monotonic": __emscripten_get_now_is_monotonic, "_mmap_js": __mmap_js, "_munmap_js": __munmap_js, "abort": _abort, "emscripten_date_now": _emscripten_date_now, "emscripten_get_heap_max": _emscripten_get_heap_max, "emscripten_get_now": _emscripten_get_now, "emscripten_memcpy_big": _emscripten_memcpy_big, "emscripten_resize_heap": _emscripten_resize_heap, "environ_get": _environ_get, "environ_sizes_get": _environ_sizes_get, "exit": _exit, "fd_close": _fd_close, "fd_seek": _fd_seek, "fd_write": _fd_write, "getentropy": _getentropy };
|
|
4001
|
+
createWasm();
|
|
4002
|
+
Module["___wasm_call_ctors"] = function() {
|
|
4003
|
+
return (Module["___wasm_call_ctors"] = Module["asm"]["__wasm_call_ctors"]).apply(null, arguments);
|
|
4004
|
+
};
|
|
4005
|
+
Module["_getModelBufferMemoryOffset"] = function() {
|
|
4006
|
+
return (Module["_getModelBufferMemoryOffset"] = Module["asm"]["getModelBufferMemoryOffset"]).apply(null, arguments);
|
|
4007
|
+
};
|
|
4008
|
+
Module["_getInputMemoryOffset"] = function() {
|
|
4009
|
+
return (Module["_getInputMemoryOffset"] = Module["asm"]["getInputMemoryOffset"]).apply(null, arguments);
|
|
4010
|
+
};
|
|
4011
|
+
Module["_getInputHeight"] = function() {
|
|
4012
|
+
return (Module["_getInputHeight"] = Module["asm"]["getInputHeight"]).apply(null, arguments);
|
|
4013
|
+
};
|
|
4014
|
+
Module["_getInputWidth"] = function() {
|
|
4015
|
+
return (Module["_getInputWidth"] = Module["asm"]["getInputWidth"]).apply(null, arguments);
|
|
4016
|
+
};
|
|
4017
|
+
Module["_getInputChannelCount"] = function() {
|
|
4018
|
+
return (Module["_getInputChannelCount"] = Module["asm"]["getInputChannelCount"]).apply(null, arguments);
|
|
4019
|
+
};
|
|
4020
|
+
Module["_getOutputMemoryOffset"] = function() {
|
|
4021
|
+
return (Module["_getOutputMemoryOffset"] = Module["asm"]["getOutputMemoryOffset"]).apply(null, arguments);
|
|
4022
|
+
};
|
|
4023
|
+
Module["_getOutputHeight"] = function() {
|
|
4024
|
+
return (Module["_getOutputHeight"] = Module["asm"]["getOutputHeight"]).apply(null, arguments);
|
|
4025
|
+
};
|
|
4026
|
+
Module["_getOutputWidth"] = function() {
|
|
4027
|
+
return (Module["_getOutputWidth"] = Module["asm"]["getOutputWidth"]).apply(null, arguments);
|
|
4028
|
+
};
|
|
4029
|
+
Module["_getOutputChannelCount"] = function() {
|
|
4030
|
+
return (Module["_getOutputChannelCount"] = Module["asm"]["getOutputChannelCount"]).apply(null, arguments);
|
|
4031
|
+
};
|
|
4032
|
+
Module["_loadModel"] = function() {
|
|
4033
|
+
return (Module["_loadModel"] = Module["asm"]["loadModel"]).apply(null, arguments);
|
|
4034
|
+
};
|
|
4035
|
+
Module["_runInference"] = function() {
|
|
4036
|
+
return (Module["_runInference"] = Module["asm"]["runInference"]).apply(null, arguments);
|
|
4037
|
+
};
|
|
4038
|
+
Module["_malloc"] = function() {
|
|
4039
|
+
return (Module["_malloc"] = Module["asm"]["malloc"]).apply(null, arguments);
|
|
4040
|
+
};
|
|
4041
|
+
Module["___errno_location"] = function() {
|
|
4042
|
+
return (Module["___errno_location"] = Module["asm"]["__errno_location"]).apply(null, arguments);
|
|
4043
|
+
};
|
|
4044
|
+
Module["___dl_seterr"] = function() {
|
|
4045
|
+
return (Module["___dl_seterr"] = Module["asm"]["__dl_seterr"]).apply(null, arguments);
|
|
4046
|
+
};
|
|
4047
|
+
Module["stackSave"] = function() {
|
|
4048
|
+
return (Module["stackSave"] = Module["asm"]["stackSave"]).apply(null, arguments);
|
|
4049
|
+
};
|
|
4050
|
+
Module["stackRestore"] = function() {
|
|
4051
|
+
return (Module["stackRestore"] = Module["asm"]["stackRestore"]).apply(null, arguments);
|
|
4052
|
+
};
|
|
4053
|
+
Module["stackAlloc"] = function() {
|
|
4054
|
+
return (Module["stackAlloc"] = Module["asm"]["stackAlloc"]).apply(null, arguments);
|
|
4055
|
+
};
|
|
4056
|
+
Module["dynCall_jjj"] = function() {
|
|
4057
|
+
return (Module["dynCall_jjj"] = Module["asm"]["dynCall_jjj"]).apply(null, arguments);
|
|
4058
|
+
};
|
|
4059
|
+
Module["dynCall_jiii"] = function() {
|
|
4060
|
+
return (Module["dynCall_jiii"] = Module["asm"]["dynCall_jiii"]).apply(null, arguments);
|
|
4061
|
+
};
|
|
4062
|
+
Module["dynCall_iiiijj"] = function() {
|
|
4063
|
+
return (Module["dynCall_iiiijj"] = Module["asm"]["dynCall_iiiijj"]).apply(null, arguments);
|
|
4064
|
+
};
|
|
4065
|
+
Module["dynCall_viijj"] = function() {
|
|
4066
|
+
return (Module["dynCall_viijj"] = Module["asm"]["dynCall_viijj"]).apply(null, arguments);
|
|
4067
|
+
};
|
|
4068
|
+
Module["dynCall_viiijjj"] = function() {
|
|
4069
|
+
return (Module["dynCall_viiijjj"] = Module["asm"]["dynCall_viiijjj"]).apply(null, arguments);
|
|
4070
|
+
};
|
|
4071
|
+
Module["dynCall_iijjiiii"] = function() {
|
|
4072
|
+
return (Module["dynCall_iijjiiii"] = Module["asm"]["dynCall_iijjiiii"]).apply(null, arguments);
|
|
4073
|
+
};
|
|
4074
|
+
Module["dynCall_jiji"] = function() {
|
|
4075
|
+
return (Module["dynCall_jiji"] = Module["asm"]["dynCall_jiji"]).apply(null, arguments);
|
|
4076
|
+
};
|
|
4077
|
+
var calledRun;
|
|
4078
|
+
dependenciesFulfilled = function runCaller() {
|
|
4079
|
+
if (!calledRun)
|
|
4080
|
+
run();
|
|
4081
|
+
if (!calledRun)
|
|
4082
|
+
dependenciesFulfilled = runCaller;
|
|
4083
|
+
};
|
|
4084
|
+
function run(args) {
|
|
4085
|
+
if (runDependencies > 0) {
|
|
4086
|
+
return;
|
|
4087
|
+
}
|
|
4088
|
+
preRun();
|
|
4089
|
+
if (runDependencies > 0) {
|
|
4090
|
+
return;
|
|
4091
|
+
}
|
|
4092
|
+
function doRun() {
|
|
4093
|
+
if (calledRun)
|
|
4094
|
+
return;
|
|
4095
|
+
calledRun = true;
|
|
4096
|
+
Module["calledRun"] = true;
|
|
4097
|
+
if (ABORT)
|
|
4098
|
+
return;
|
|
4099
|
+
initRuntime();
|
|
4100
|
+
readyPromiseResolve(Module);
|
|
4101
|
+
if (Module["onRuntimeInitialized"])
|
|
4102
|
+
Module["onRuntimeInitialized"]();
|
|
4103
|
+
postRun();
|
|
4104
|
+
}
|
|
4105
|
+
if (Module["setStatus"]) {
|
|
4106
|
+
Module["setStatus"]("Running...");
|
|
4107
|
+
setTimeout(function() {
|
|
4108
|
+
setTimeout(function() {
|
|
4109
|
+
Module["setStatus"]("");
|
|
4110
|
+
}, 1);
|
|
4111
|
+
doRun();
|
|
4112
|
+
}, 1);
|
|
4113
|
+
} else {
|
|
4114
|
+
doRun();
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
if (Module["preInit"]) {
|
|
4118
|
+
if (typeof Module["preInit"] == "function")
|
|
4119
|
+
Module["preInit"] = [Module["preInit"]];
|
|
4120
|
+
while (Module["preInit"].length > 0) {
|
|
4121
|
+
Module["preInit"].pop()();
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
run();
|
|
4125
|
+
return createTFLiteSIMDModule2.ready;
|
|
4126
|
+
};
|
|
4127
|
+
})();
|
|
4128
|
+
async function useTFLite(segmentationConfig) {
|
|
4129
|
+
let tflite = null;
|
|
4130
|
+
let tfliteSIMD = null;
|
|
4131
|
+
let selectedTFLite = null;
|
|
4132
|
+
let isSIMDSupported = false;
|
|
4133
|
+
async function loadTFLite() {
|
|
4134
|
+
tflite = await createTFLiteModule();
|
|
4135
|
+
try {
|
|
4136
|
+
const createdTFLiteSIMD = await createTFLiteSIMDModule();
|
|
4137
|
+
tfliteSIMD = createdTFLiteSIMD;
|
|
4138
|
+
isSIMDSupported = true;
|
|
4139
|
+
segmentationConfig.backend = "wasmSimd";
|
|
4140
|
+
} catch (error) {
|
|
4141
|
+
console.warn("Failed to create TFLite SIMD WebAssembly module.", error);
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
await loadTFLite();
|
|
4145
|
+
async function loadTFLiteModel() {
|
|
4146
|
+
if (!tflite || isSIMDSupported && !tfliteSIMD || !isSIMDSupported && segmentationConfig.backend === "wasmSimd" || segmentationConfig.model !== "meet" && segmentationConfig.model !== "mlkit") {
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
selectedTFLite = null;
|
|
4150
|
+
const newSelectedTFLite = segmentationConfig.backend === "wasmSimd" ? tfliteSIMD : tflite;
|
|
4151
|
+
if (!newSelectedTFLite) {
|
|
4152
|
+
throw new Error(
|
|
4153
|
+
`TFLite backend unavailable: ${segmentationConfig.backend}`
|
|
4154
|
+
);
|
|
4155
|
+
}
|
|
4156
|
+
const modelFileName = getTFLiteModelFileName(
|
|
4157
|
+
segmentationConfig.model,
|
|
4158
|
+
segmentationConfig.inputResolution
|
|
4159
|
+
);
|
|
4160
|
+
const modelResponse = await fetch(
|
|
4161
|
+
`https://dyte-plugins.s3.ap-south-1.amazonaws.com/tf-assets/models/${modelFileName}.tflite`
|
|
4162
|
+
);
|
|
4163
|
+
const model = await modelResponse.arrayBuffer();
|
|
4164
|
+
const modelBufferOffset = newSelectedTFLite._getModelBufferMemoryOffset();
|
|
4165
|
+
newSelectedTFLite.HEAPU8.set(new Uint8Array(model), modelBufferOffset);
|
|
4166
|
+
newSelectedTFLite._loadModel(model.byteLength);
|
|
4167
|
+
selectedTFLite = newSelectedTFLite;
|
|
4168
|
+
}
|
|
4169
|
+
await loadTFLiteModel();
|
|
4170
|
+
return { tflite: selectedTFLite, isSIMDSupported };
|
|
4171
|
+
}
|
|
4172
|
+
const _RealtimeKitVideoBackgroundTransformer = class {
|
|
4173
|
+
constructor(imageBackgroundTransformer, simpleBackgroundTransformer) {
|
|
4174
|
+
__privateAdd(this, _imageBackgroundTransformer, void 0);
|
|
4175
|
+
__privateAdd(this, _simpleBackgroundTrasnformer, void 0);
|
|
4176
|
+
__privateSet(this, _imageBackgroundTransformer, imageBackgroundTransformer);
|
|
4177
|
+
__privateSet(this, _simpleBackgroundTrasnformer, simpleBackgroundTransformer);
|
|
4178
|
+
}
|
|
4179
|
+
static async init({
|
|
4180
|
+
meeting,
|
|
4181
|
+
segmentationConfig: passedSegmentationConfig,
|
|
4182
|
+
postProcessingConfig: passedPostProcessingConfig
|
|
4183
|
+
}) {
|
|
4184
|
+
if (!this.isSupported()) {
|
|
4185
|
+
console.error("Initialising it in an unsupported environment, the middleware might not work");
|
|
4186
|
+
}
|
|
4187
|
+
window.addEventListener("error", (event) => {
|
|
4188
|
+
var _a;
|
|
4189
|
+
if (!((_a = event.filename) == null ? void 0 : _a.includes("localhost")) && event.lineno !== 0) {
|
|
4190
|
+
console.error("RealtimeKitVideoBackgroundTransformer::UnhandledError", event.error);
|
|
4191
|
+
}
|
|
4192
|
+
});
|
|
4193
|
+
window.addEventListener("unhandledrejection", (error) => {
|
|
4194
|
+
console.error("RealtimeKitVideoBackgroundTransformer::UnhandledRejection", error.reason);
|
|
4195
|
+
});
|
|
4196
|
+
const segmentationConfig = {
|
|
4197
|
+
model: "mlkit",
|
|
4198
|
+
backend: "wasmSimd",
|
|
4199
|
+
inputResolution: "256x256",
|
|
4200
|
+
pipeline: "webgl2",
|
|
4201
|
+
targetFps: 35,
|
|
4202
|
+
deferInputResizing: true,
|
|
4203
|
+
...passedSegmentationConfig || {}
|
|
4204
|
+
};
|
|
4205
|
+
const browser = getBrowser();
|
|
4206
|
+
if (browser.getEngineName() === "WebKit") {
|
|
4207
|
+
segmentationConfig.pipeline = "canvas2dCpu";
|
|
4208
|
+
}
|
|
4209
|
+
const postProcessingConfig = {
|
|
4210
|
+
smoothSegmentationMask: true,
|
|
4211
|
+
jointBilateralFilter: { sigmaSpace: 1, sigmaColor: 0.1 },
|
|
4212
|
+
coverage: [0.5, 0.75],
|
|
4213
|
+
lightWrapping: 0.3,
|
|
4214
|
+
blendMode: "screen",
|
|
4215
|
+
...passedPostProcessingConfig || {}
|
|
4216
|
+
};
|
|
4217
|
+
await meeting.self.setVideoMiddlewareGlobalConfig({ disablePerFrameCanvasRendering: true });
|
|
4218
|
+
const { tflite } = await useTFLite(segmentationConfig);
|
|
4219
|
+
return new _RealtimeKitVideoBackgroundTransformer(
|
|
4220
|
+
await ImageBackgroundTransformer.init({
|
|
4221
|
+
meeting,
|
|
4222
|
+
segmentationConfig,
|
|
4223
|
+
postProcessingConfig,
|
|
4224
|
+
tflite
|
|
4225
|
+
}),
|
|
4226
|
+
await SimpleBackgroundTransformer.init({
|
|
4227
|
+
meeting,
|
|
4228
|
+
segmentationConfig,
|
|
4229
|
+
postProcessingConfig,
|
|
4230
|
+
tflite
|
|
4231
|
+
})
|
|
4232
|
+
);
|
|
4233
|
+
}
|
|
4234
|
+
static isSupported() {
|
|
4235
|
+
var _a;
|
|
4236
|
+
let isMiddlewareSupported = false;
|
|
4237
|
+
try {
|
|
4238
|
+
const browser = getBrowser();
|
|
4239
|
+
const dummyCanvas = document.createElement("canvas");
|
|
4240
|
+
const context = dummyCanvas.getContext("webgl2", {}) || dummyCanvas.getContext("webgl", {});
|
|
4241
|
+
const browserMajorVersion = +((_a = browser.getBrowserVersion()) == null ? void 0 : _a.split(".")[0]);
|
|
4242
|
+
if (!context || browser.getOSName() === "iOS" || browser.getBrowserName() === "Safari" && browserMajorVersion < 17) {
|
|
4243
|
+
return false;
|
|
4244
|
+
}
|
|
4245
|
+
isMiddlewareSupported = true;
|
|
4246
|
+
} catch {
|
|
4247
|
+
isMiddlewareSupported = false;
|
|
4248
|
+
}
|
|
4249
|
+
return isMiddlewareSupported;
|
|
4250
|
+
}
|
|
4251
|
+
async createStaticBackgroundVideoMiddleware(staticBackgroundImageURL) {
|
|
4252
|
+
const staticBackgroundVideoMiddleware = await __privateGet(this, _imageBackgroundTransformer).createStaticBackgroundImageVideoMiddleware(staticBackgroundImageURL);
|
|
4253
|
+
return staticBackgroundVideoMiddleware;
|
|
4254
|
+
}
|
|
4255
|
+
async createBackgroundBlurVideoMiddleware(blurLength = 50) {
|
|
4256
|
+
return __privateGet(this, _simpleBackgroundTrasnformer).createBackgroundBlurVideoMiddleware(blurLength);
|
|
4257
|
+
}
|
|
4258
|
+
destruct() {
|
|
4259
|
+
__privateGet(this, _imageBackgroundTransformer).destruct();
|
|
4260
|
+
__privateGet(this, _simpleBackgroundTrasnformer).destruct();
|
|
4261
|
+
}
|
|
4262
|
+
};
|
|
4263
|
+
let RealtimeKitVideoBackgroundTransformer = _RealtimeKitVideoBackgroundTransformer;
|
|
4264
|
+
_imageBackgroundTransformer = new WeakMap();
|
|
4265
|
+
_simpleBackgroundTrasnformer = new WeakMap();
|
|
4266
|
+
export { RealtimeKitVideoBackgroundTransformer as default };
|