@livekit/track-processors 0.5.3 → 0.5.5
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/dist/index.js +474 -267
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +474 -267
- package/dist/index.mjs.map +1 -1
- package/dist/src/transformers/BackgroundTransformer.d.ts +3 -1
- package/dist/src/webgl/index.d.ts +2 -4
- package/dist/src/webgl/shader-programs/blurShader.d.ts +14 -0
- package/dist/src/webgl/shader-programs/boxBlurShader.d.ts +16 -0
- package/dist/src/webgl/shader-programs/compositeShader.d.ts +18 -0
- package/dist/src/webgl/shader-programs/downSampler.d.ts +12 -0
- package/dist/src/webgl/shader-programs/vertexShader.d.ts +1 -0
- package/dist/src/webgl/utils.d.ts +25 -0
- package/package.json +1 -1
- package/src/index.ts +9 -11
- package/src/transformers/BackgroundTransformer.ts +42 -28
- package/src/webgl/index.ts +180 -345
- package/src/webgl/shader-programs/blurShader.ts +108 -0
- package/src/webgl/shader-programs/boxBlurShader.ts +60 -0
- package/src/webgl/shader-programs/compositeShader.ts +64 -0
- package/src/webgl/shader-programs/downSampler.ts +94 -0
- package/src/webgl/shader-programs/vertexShader.ts +11 -0
- package/src/webgl/utils.ts +142 -0
package/dist/index.js
CHANGED
|
@@ -251,14 +251,112 @@ var dependencies = {
|
|
|
251
251
|
"@mediapipe/tasks-vision": "0.10.14"
|
|
252
252
|
};
|
|
253
253
|
|
|
254
|
-
// src/webgl/
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
// src/webgl/utils.ts
|
|
255
|
+
function initTexture(gl, texIndex) {
|
|
256
|
+
const texRef = gl.TEXTURE0 + texIndex;
|
|
257
|
+
gl.activeTexture(texRef);
|
|
258
|
+
const texture = gl.createTexture();
|
|
259
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
260
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
261
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
262
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
263
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
264
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
265
|
+
return texture;
|
|
266
|
+
}
|
|
267
|
+
function createShader(gl, type, source) {
|
|
268
|
+
const shader = gl.createShader(type);
|
|
269
|
+
gl.shaderSource(shader, source);
|
|
270
|
+
gl.compileShader(shader);
|
|
271
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
272
|
+
console.error("Shader compile failed:", gl.getShaderInfoLog(shader));
|
|
273
|
+
gl.deleteShader(shader);
|
|
274
|
+
throw new Error("Shader compile failed");
|
|
275
|
+
}
|
|
276
|
+
return shader;
|
|
277
|
+
}
|
|
278
|
+
function createProgram(gl, vs, fs) {
|
|
279
|
+
const program = gl.createProgram();
|
|
280
|
+
gl.attachShader(program, vs);
|
|
281
|
+
gl.attachShader(program, fs);
|
|
282
|
+
gl.linkProgram(program);
|
|
283
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
284
|
+
console.error("Program link failed:", gl.getProgramInfoLog(program));
|
|
285
|
+
throw new Error("Program link failed");
|
|
286
|
+
}
|
|
287
|
+
return program;
|
|
288
|
+
}
|
|
289
|
+
function createFramebuffer(gl, texture, width, height) {
|
|
290
|
+
const framebuffer = gl.createFramebuffer();
|
|
291
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
292
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
293
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
294
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
295
|
+
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
|
296
|
+
if (status !== gl.FRAMEBUFFER_COMPLETE) {
|
|
297
|
+
throw new Error("Framebuffer not complete");
|
|
298
|
+
}
|
|
299
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
300
|
+
return framebuffer;
|
|
301
|
+
}
|
|
302
|
+
function createVertexBuffer(gl) {
|
|
303
|
+
const vertexBuffer = gl.createBuffer();
|
|
304
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
305
|
+
gl.bufferData(
|
|
306
|
+
gl.ARRAY_BUFFER,
|
|
307
|
+
new Float32Array([-1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1]),
|
|
308
|
+
gl.STATIC_DRAW
|
|
309
|
+
);
|
|
310
|
+
return vertexBuffer;
|
|
311
|
+
}
|
|
312
|
+
async function resizeImageToCover(image, targetWidth, targetHeight) {
|
|
313
|
+
const imgAspect = image.width / image.height;
|
|
314
|
+
const targetAspect = targetWidth / targetHeight;
|
|
315
|
+
let sx = 0;
|
|
316
|
+
let sy = 0;
|
|
317
|
+
let sWidth = image.width;
|
|
318
|
+
let sHeight = image.height;
|
|
319
|
+
if (imgAspect > targetAspect) {
|
|
320
|
+
sWidth = Math.round(image.height * targetAspect);
|
|
321
|
+
sx = Math.round((image.width - sWidth) / 2);
|
|
322
|
+
} else if (imgAspect < targetAspect) {
|
|
323
|
+
sHeight = Math.round(image.width / targetAspect);
|
|
324
|
+
sy = Math.round((image.height - sHeight) / 2);
|
|
325
|
+
}
|
|
326
|
+
return createImageBitmap(image, sx, sy, sWidth, sHeight, {
|
|
327
|
+
resizeWidth: targetWidth,
|
|
328
|
+
resizeHeight: targetHeight,
|
|
329
|
+
resizeQuality: "medium"
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
var emptyImageData = new ImageData(2, 2);
|
|
333
|
+
emptyImageData.data[0] = 0;
|
|
334
|
+
emptyImageData.data[1] = 0;
|
|
335
|
+
emptyImageData.data[2] = 0;
|
|
336
|
+
emptyImageData.data[3] = 0;
|
|
337
|
+
var glsl = (source) => source;
|
|
338
|
+
|
|
339
|
+
// src/webgl/shader-programs/vertexShader.ts
|
|
340
|
+
var vertexShaderSource = (flipY = true) => `#version 300 es
|
|
341
|
+
in vec2 position;
|
|
342
|
+
out vec2 texCoords;
|
|
343
|
+
|
|
344
|
+
void main() {
|
|
345
|
+
texCoords = (position + 1.0) / 2.0;
|
|
346
|
+
texCoords.y = ${flipY ? "1.0 - texCoords.y" : "texCoords.y"};
|
|
347
|
+
gl_Position = vec4(position, 0, 1.0);
|
|
348
|
+
}
|
|
349
|
+
`;
|
|
350
|
+
|
|
351
|
+
// src/webgl/shader-programs/blurShader.ts
|
|
352
|
+
var blurFragmentShader = glsl`#version 300 es
|
|
353
|
+
precision mediump float;
|
|
354
|
+
in vec2 texCoords;
|
|
258
355
|
uniform sampler2D u_texture;
|
|
259
356
|
uniform vec2 u_texelSize;
|
|
260
357
|
uniform vec2 u_direction;
|
|
261
358
|
uniform float u_radius;
|
|
359
|
+
out vec4 fragColor;
|
|
262
360
|
|
|
263
361
|
void main() {
|
|
264
362
|
float sigma = u_radius;
|
|
@@ -273,93 +371,18 @@ var blurFragmentShader = `
|
|
|
273
371
|
if (abs(offset) > float(radius)) continue;
|
|
274
372
|
float weight = exp(-(offset * offset) / twoSigmaSq);
|
|
275
373
|
vec2 sampleCoord = texCoords + u_direction * u_texelSize * offset;
|
|
276
|
-
result +=
|
|
374
|
+
result += texture(u_texture, sampleCoord).rgb * weight;
|
|
277
375
|
totalWeight += weight;
|
|
278
376
|
}
|
|
279
377
|
|
|
280
|
-
|
|
378
|
+
fragColor = vec4(result / totalWeight, 1.0);
|
|
281
379
|
}
|
|
282
380
|
`;
|
|
283
|
-
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
void main() {
|
|
289
|
-
texCoords = (position + 1.0) / 2.0;
|
|
290
|
-
texCoords.y = 1.0 - texCoords.y;
|
|
291
|
-
gl_Position = vec4(position, 0, 1.0);
|
|
292
|
-
}
|
|
293
|
-
`;
|
|
294
|
-
const cS = `
|
|
295
|
-
precision highp float;
|
|
296
|
-
varying vec2 texCoords;
|
|
297
|
-
uniform sampler2D background;
|
|
298
|
-
uniform sampler2D frame;
|
|
299
|
-
uniform sampler2D mask;
|
|
300
|
-
void main() {
|
|
301
|
-
vec4 maskTex = texture2D(mask, texCoords);
|
|
302
|
-
vec4 frameTex = texture2D(frame, texCoords);
|
|
303
|
-
vec4 bgTex = texture2D(background, texCoords);
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
float a = maskTex.r;
|
|
307
|
-
|
|
308
|
-
gl_FragColor = mix(bgTex, vec4(frameTex.rgb, 1.0), 1.0 - a);
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
`;
|
|
312
|
-
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
313
|
-
if (!vertexShader) {
|
|
314
|
-
throw Error("can not create vertex shader");
|
|
315
|
-
}
|
|
316
|
-
gl.shaderSource(vertexShader, vs);
|
|
317
|
-
gl.compileShader(vertexShader);
|
|
318
|
-
const compositeShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
319
|
-
if (!compositeShader) {
|
|
320
|
-
throw Error("can not create fragment shader");
|
|
321
|
-
}
|
|
322
|
-
gl.shaderSource(compositeShader, cS);
|
|
323
|
-
gl.compileShader(compositeShader);
|
|
324
|
-
const compositeProgram = gl.createProgram();
|
|
325
|
-
if (!compositeProgram) {
|
|
326
|
-
throw Error("can not create composite program");
|
|
327
|
-
}
|
|
328
|
-
gl.attachShader(compositeProgram, vertexShader);
|
|
329
|
-
gl.attachShader(compositeProgram, compositeShader);
|
|
330
|
-
gl.linkProgram(compositeProgram);
|
|
331
|
-
let blurProgram = null;
|
|
332
|
-
let blurVertexShader = null;
|
|
333
|
-
let blurFrag = null;
|
|
334
|
-
let blurUniforms = null;
|
|
335
|
-
blurFrag = gl.createShader(gl.FRAGMENT_SHADER);
|
|
336
|
-
if (!blurFrag) {
|
|
337
|
-
throw Error("can not create blur shader");
|
|
338
|
-
}
|
|
339
|
-
gl.shaderSource(blurFrag, blurFragmentShader);
|
|
340
|
-
gl.compileShader(blurFrag);
|
|
341
|
-
if (!gl.getShaderParameter(blurFrag, gl.COMPILE_STATUS)) {
|
|
342
|
-
const info = gl.getShaderInfoLog(blurFrag);
|
|
343
|
-
throw Error(`Failed to compile blur shader: ${info}`);
|
|
344
|
-
}
|
|
345
|
-
blurVertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
346
|
-
if (!blurVertexShader) {
|
|
347
|
-
throw Error("can not create blur vertex shader");
|
|
348
|
-
}
|
|
349
|
-
gl.shaderSource(blurVertexShader, vs);
|
|
350
|
-
gl.compileShader(blurVertexShader);
|
|
351
|
-
blurProgram = gl.createProgram();
|
|
352
|
-
if (!blurProgram) {
|
|
353
|
-
throw Error("can not create blur program");
|
|
354
|
-
}
|
|
355
|
-
gl.attachShader(blurProgram, blurVertexShader);
|
|
356
|
-
gl.attachShader(blurProgram, blurFrag);
|
|
357
|
-
gl.linkProgram(blurProgram);
|
|
358
|
-
if (!gl.getProgramParameter(blurProgram, gl.LINK_STATUS)) {
|
|
359
|
-
const info = gl.getProgramInfoLog(blurProgram);
|
|
360
|
-
throw Error(`Failed to link blur program: ${info}`);
|
|
361
|
-
}
|
|
362
|
-
blurUniforms = {
|
|
381
|
+
function createBlurProgram(gl) {
|
|
382
|
+
const blurVertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource());
|
|
383
|
+
const blurFrag = createShader(gl, gl.FRAGMENT_SHADER, blurFragmentShader);
|
|
384
|
+
const blurProgram = createProgram(gl, blurVertexShader, blurFrag);
|
|
385
|
+
const blurUniforms = {
|
|
363
386
|
position: gl.getAttribLocation(blurProgram, "position"),
|
|
364
387
|
texture: gl.getUniformLocation(blurProgram, "u_texture"),
|
|
365
388
|
texelSize: gl.getUniformLocation(blurProgram, "u_texelSize"),
|
|
@@ -367,123 +390,267 @@ var createShaderProgram = (gl) => {
|
|
|
367
390
|
radius: gl.getUniformLocation(blurProgram, "u_radius")
|
|
368
391
|
};
|
|
369
392
|
return {
|
|
393
|
+
program: blurProgram,
|
|
394
|
+
shader: blurFrag,
|
|
395
|
+
vertexShader: blurVertexShader,
|
|
396
|
+
uniforms: blurUniforms
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function applyBlur(gl, sourceTexture, width, height, blurRadius, blurProgram, blurUniforms, vertexBuffer, processFramebuffers, processTextures) {
|
|
400
|
+
gl.useProgram(blurProgram);
|
|
401
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
402
|
+
gl.vertexAttribPointer(blurUniforms.position, 2, gl.FLOAT, false, 0, 0);
|
|
403
|
+
gl.enableVertexAttribArray(blurUniforms.position);
|
|
404
|
+
const texelWidth = 1 / width;
|
|
405
|
+
const texelHeight = 1 / height;
|
|
406
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, processFramebuffers[0]);
|
|
407
|
+
gl.viewport(0, 0, width, height);
|
|
408
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
409
|
+
gl.bindTexture(gl.TEXTURE_2D, sourceTexture);
|
|
410
|
+
gl.uniform1i(blurUniforms.texture, 0);
|
|
411
|
+
gl.uniform2f(blurUniforms.texelSize, texelWidth, texelHeight);
|
|
412
|
+
gl.uniform2f(blurUniforms.direction, 1, 0);
|
|
413
|
+
gl.uniform1f(blurUniforms.radius, blurRadius);
|
|
414
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
415
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, processFramebuffers[1]);
|
|
416
|
+
gl.viewport(0, 0, width, height);
|
|
417
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
418
|
+
gl.bindTexture(gl.TEXTURE_2D, processTextures[0]);
|
|
419
|
+
gl.uniform1i(blurUniforms.texture, 0);
|
|
420
|
+
gl.uniform2f(blurUniforms.direction, 0, 1);
|
|
421
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
422
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
423
|
+
return processTextures[1];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/webgl/shader-programs/boxBlurShader.ts
|
|
427
|
+
var boxBlurFragmentShader = glsl`#version 300 es
|
|
428
|
+
precision mediump float;
|
|
429
|
+
|
|
430
|
+
in vec2 texCoords;
|
|
431
|
+
|
|
432
|
+
uniform sampler2D u_texture;
|
|
433
|
+
uniform vec2 u_texelSize; // 1.0 / texture size
|
|
434
|
+
uniform vec2 u_direction; // (1.0, 0.0) for horizontal, (0.0, 1.0) for vertical
|
|
435
|
+
uniform float u_radius; // blur radius in texels
|
|
436
|
+
|
|
437
|
+
out vec4 fragColor;
|
|
438
|
+
|
|
439
|
+
void main() {
|
|
440
|
+
vec3 sum = vec3(0.0);
|
|
441
|
+
float count = 0.0;
|
|
442
|
+
|
|
443
|
+
// Limit radius to avoid excessive loop cost
|
|
444
|
+
const int MAX_RADIUS = 16;
|
|
445
|
+
int radius = int(min(float(MAX_RADIUS), u_radius));
|
|
446
|
+
|
|
447
|
+
for (int i = -MAX_RADIUS; i <= MAX_RADIUS; ++i) {
|
|
448
|
+
if (abs(i) > radius) continue;
|
|
449
|
+
|
|
450
|
+
vec2 offset = u_direction * u_texelSize * float(i);
|
|
451
|
+
sum += texture(u_texture, texCoords + offset).rgb;
|
|
452
|
+
count += 1.0;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
fragColor = vec4(sum / count, 1.0);
|
|
456
|
+
}
|
|
457
|
+
`;
|
|
458
|
+
function createBoxBlurProgram(gl) {
|
|
459
|
+
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource());
|
|
460
|
+
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, boxBlurFragmentShader);
|
|
461
|
+
const program = createProgram(gl, vertexShader, fragmentShader);
|
|
462
|
+
const uniforms = {
|
|
463
|
+
position: gl.getAttribLocation(program, "position"),
|
|
464
|
+
texture: gl.getUniformLocation(program, "u_texture"),
|
|
465
|
+
texelSize: gl.getUniformLocation(program, "u_texelSize"),
|
|
466
|
+
direction: gl.getUniformLocation(program, "u_direction"),
|
|
467
|
+
radius: gl.getUniformLocation(program, "u_radius")
|
|
468
|
+
};
|
|
469
|
+
return {
|
|
470
|
+
program,
|
|
370
471
|
vertexShader,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
compositeProgram,
|
|
374
|
-
blurProgram,
|
|
375
|
-
attribLocations: {
|
|
376
|
-
position: gl.getAttribLocation(compositeProgram, "position")
|
|
377
|
-
},
|
|
378
|
-
uniformLocations: {
|
|
379
|
-
mask: gl.getUniformLocation(compositeProgram, "mask"),
|
|
380
|
-
frame: gl.getUniformLocation(compositeProgram, "frame"),
|
|
381
|
-
background: gl.getUniformLocation(compositeProgram, "background")
|
|
382
|
-
},
|
|
383
|
-
blurUniforms
|
|
472
|
+
fragmentShader,
|
|
473
|
+
uniforms
|
|
384
474
|
};
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// src/webgl/shader-programs/compositeShader.ts
|
|
478
|
+
var compositeFragmentShader = glsl`#version 300 es
|
|
479
|
+
precision mediump float;
|
|
480
|
+
in vec2 texCoords;
|
|
481
|
+
uniform sampler2D background;
|
|
482
|
+
uniform sampler2D frame;
|
|
483
|
+
uniform sampler2D mask;
|
|
484
|
+
out vec4 fragColor;
|
|
485
|
+
|
|
486
|
+
void main() {
|
|
487
|
+
|
|
488
|
+
vec4 frameTex = texture(frame, texCoords);
|
|
489
|
+
vec4 bgTex = texture(background, texCoords);
|
|
490
|
+
|
|
491
|
+
float maskVal = texture(mask, texCoords).r;
|
|
492
|
+
|
|
493
|
+
// Compute screen-space gradient to detect edge sharpness
|
|
494
|
+
float grad = length(vec2(dFdx(maskVal), dFdy(maskVal)));
|
|
495
|
+
|
|
496
|
+
float edgeSoftness = 2.0; // higher = softer
|
|
497
|
+
|
|
498
|
+
// Create a smooth edge around binary transition
|
|
499
|
+
float smoothAlpha = smoothstep(0.5 - grad * edgeSoftness, 0.5 + grad * edgeSoftness, maskVal);
|
|
500
|
+
|
|
501
|
+
// Optional: preserve frame alpha, or override as fully opaque
|
|
502
|
+
vec4 blended = mix(bgTex, vec4(frameTex.rgb, 1.0), 1.0 - smoothAlpha);
|
|
503
|
+
|
|
504
|
+
fragColor = blended;
|
|
505
|
+
|
|
506
|
+
}
|
|
507
|
+
`;
|
|
508
|
+
function createCompositeProgram(gl) {
|
|
509
|
+
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource());
|
|
510
|
+
const compositeShader = createShader(gl, gl.FRAGMENT_SHADER, compositeFragmentShader);
|
|
511
|
+
const compositeProgram = createProgram(gl, vertexShader, compositeShader);
|
|
512
|
+
const attribLocations = {
|
|
513
|
+
position: gl.getAttribLocation(compositeProgram, "position")
|
|
514
|
+
};
|
|
515
|
+
const uniformLocations = {
|
|
516
|
+
mask: gl.getUniformLocation(compositeProgram, "mask"),
|
|
517
|
+
frame: gl.getUniformLocation(compositeProgram, "frame"),
|
|
518
|
+
background: gl.getUniformLocation(compositeProgram, "background"),
|
|
519
|
+
stepWidth: gl.getUniformLocation(compositeProgram, "u_stepWidth")
|
|
520
|
+
};
|
|
521
|
+
return {
|
|
522
|
+
program: compositeProgram,
|
|
523
|
+
vertexShader,
|
|
524
|
+
fragmentShader: compositeShader,
|
|
525
|
+
attribLocations,
|
|
526
|
+
uniformLocations
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// src/webgl/shader-programs/downSampler.ts
|
|
531
|
+
function createDownSampler(gl, width, height) {
|
|
389
532
|
const texture = gl.createTexture();
|
|
390
533
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
391
|
-
gl.
|
|
392
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
534
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
393
535
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
394
536
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
395
|
-
gl.
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
function createFramebuffer(gl, texture, width, height) {
|
|
537
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
538
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
399
539
|
const framebuffer = gl.createFramebuffer();
|
|
400
540
|
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
401
541
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
542
|
+
const vertexSource = `
|
|
543
|
+
attribute vec2 position;
|
|
544
|
+
varying vec2 v_uv;
|
|
545
|
+
void main() {
|
|
546
|
+
v_uv = (position + 1.0) * 0.5;
|
|
547
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
548
|
+
}
|
|
549
|
+
`;
|
|
550
|
+
const fragmentSource = `
|
|
551
|
+
precision mediump float;
|
|
552
|
+
varying vec2 v_uv;
|
|
553
|
+
uniform sampler2D u_texture;
|
|
554
|
+
void main() {
|
|
555
|
+
gl_FragColor = texture2D(u_texture, v_uv);
|
|
556
|
+
}
|
|
557
|
+
`;
|
|
558
|
+
const vertShader = createShader(gl, gl.VERTEX_SHADER, vertexSource);
|
|
559
|
+
const fragShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource);
|
|
560
|
+
const program = createProgram(gl, vertShader, fragShader);
|
|
561
|
+
const uniforms = {
|
|
562
|
+
texture: gl.getUniformLocation(program, "u_texture"),
|
|
563
|
+
position: gl.getAttribLocation(program, "position")
|
|
564
|
+
};
|
|
565
|
+
return {
|
|
566
|
+
framebuffer,
|
|
567
|
+
texture,
|
|
568
|
+
program,
|
|
569
|
+
uniforms
|
|
570
|
+
};
|
|
410
571
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const vertexBuffer = gl.createBuffer();
|
|
572
|
+
function applyDownsampling(gl, inputTexture, downSampler, vertexBuffer, width, height) {
|
|
573
|
+
gl.useProgram(downSampler.program);
|
|
574
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, downSampler.framebuffer);
|
|
575
|
+
gl.viewport(0, 0, width, height);
|
|
416
576
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
417
|
-
gl.
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
|
|
577
|
+
gl.enableVertexAttribArray(downSampler.uniforms.position);
|
|
578
|
+
gl.vertexAttribPointer(downSampler.uniforms.position, 2, gl.FLOAT, false, 0, 0);
|
|
579
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
580
|
+
gl.bindTexture(gl.TEXTURE_2D, inputTexture);
|
|
581
|
+
gl.uniform1i(downSampler.uniforms.texture, 0);
|
|
582
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
583
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
584
|
+
return downSampler.texture;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// src/webgl/index.ts
|
|
424
588
|
var setupWebGL = (canvas) => {
|
|
425
|
-
const gl = canvas.getContext("webgl2", {
|
|
589
|
+
const gl = canvas.getContext("webgl2", {
|
|
590
|
+
antialias: true,
|
|
591
|
+
premultipliedAlpha: true
|
|
592
|
+
});
|
|
426
593
|
let blurRadius = null;
|
|
594
|
+
let maskBlurRadius = 8;
|
|
595
|
+
const downsampleFactor = 4;
|
|
427
596
|
if (!gl) {
|
|
597
|
+
console.error("Failed to create WebGL context");
|
|
428
598
|
return void 0;
|
|
429
599
|
}
|
|
430
600
|
gl.enable(gl.BLEND);
|
|
431
601
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
602
|
+
const composite = createCompositeProgram(gl);
|
|
603
|
+
const compositeProgram = composite.program;
|
|
604
|
+
const positionLocation = composite.attribLocations.position;
|
|
432
605
|
const {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
606
|
+
mask: maskTextureLocation,
|
|
607
|
+
frame: frameTextureLocation,
|
|
608
|
+
background: bgTextureLocation
|
|
609
|
+
} = composite.uniformLocations;
|
|
610
|
+
const blur = createBlurProgram(gl);
|
|
611
|
+
const blurProgram = blur.program;
|
|
612
|
+
const blurUniforms = blur.uniforms;
|
|
613
|
+
const boxBlur = createBoxBlurProgram(gl);
|
|
614
|
+
const boxBlurProgram = boxBlur.program;
|
|
615
|
+
const boxBlurUniforms = boxBlur.uniforms;
|
|
443
616
|
const bgTexture = initTexture(gl, 0);
|
|
444
617
|
const frameTexture = initTexture(gl, 1);
|
|
445
618
|
const vertexBuffer = createVertexBuffer(gl);
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
619
|
+
if (!vertexBuffer) {
|
|
620
|
+
throw new Error("Failed to create vertex buffer");
|
|
621
|
+
}
|
|
622
|
+
let bgBlurTextures = [];
|
|
623
|
+
let bgBlurFrameBuffers = [];
|
|
624
|
+
let blurredMaskTexture = null;
|
|
625
|
+
let finalMaskTextures = [];
|
|
626
|
+
let readMaskIndex = 0;
|
|
627
|
+
let writeMaskIndex = 1;
|
|
628
|
+
bgBlurTextures.push(initTexture(gl, 3));
|
|
629
|
+
bgBlurTextures.push(initTexture(gl, 4));
|
|
630
|
+
const bgBlurTextureWidth = Math.floor(canvas.width / downsampleFactor);
|
|
631
|
+
const bgBlurTextureHeight = Math.floor(canvas.height / downsampleFactor);
|
|
632
|
+
const downSampler = createDownSampler(gl, bgBlurTextureWidth, bgBlurTextureHeight);
|
|
633
|
+
bgBlurFrameBuffers.push(
|
|
634
|
+
createFramebuffer(gl, bgBlurTextures[0], bgBlurTextureWidth, bgBlurTextureHeight)
|
|
635
|
+
);
|
|
636
|
+
bgBlurFrameBuffers.push(
|
|
637
|
+
createFramebuffer(gl, bgBlurTextures[1], bgBlurTextureWidth, bgBlurTextureHeight)
|
|
638
|
+
);
|
|
639
|
+
const tempMaskTexture = initTexture(gl, 5);
|
|
640
|
+
const tempMaskFrameBuffer = createFramebuffer(gl, tempMaskTexture, canvas.width, canvas.height);
|
|
641
|
+
finalMaskTextures.push(initTexture(gl, 6));
|
|
642
|
+
finalMaskTextures.push(initTexture(gl, 7));
|
|
643
|
+
const finalMaskFrameBuffers = [
|
|
644
|
+
createFramebuffer(gl, finalMaskTextures[0], canvas.width, canvas.height),
|
|
645
|
+
createFramebuffer(gl, finalMaskTextures[1], canvas.width, canvas.height)
|
|
646
|
+
];
|
|
452
647
|
gl.useProgram(compositeProgram);
|
|
453
648
|
gl.uniform1i(bgTextureLocation, 0);
|
|
454
649
|
gl.uniform1i(frameTextureLocation, 1);
|
|
455
650
|
gl.uniform1i(maskTextureLocation, 2);
|
|
456
|
-
let customBackgroundImage =
|
|
457
|
-
function
|
|
458
|
-
if (
|
|
459
|
-
return bgTexture;
|
|
460
|
-
gl.useProgram(blurProgram);
|
|
461
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
462
|
-
gl.vertexAttribPointer(blurUniforms.position, 2, gl.FLOAT, false, 0, 0);
|
|
463
|
-
gl.enableVertexAttribArray(blurUniforms.position);
|
|
464
|
-
const texelWidth = 1 / width;
|
|
465
|
-
const texelHeight = 1 / height;
|
|
466
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, processFramebuffers[0]);
|
|
467
|
-
gl.viewport(0, 0, width, height);
|
|
468
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
469
|
-
gl.bindTexture(gl.TEXTURE_2D, sourceTexture);
|
|
470
|
-
gl.uniform1i(blurUniforms.texture, 0);
|
|
471
|
-
gl.uniform2f(blurUniforms.texelSize, texelWidth, texelHeight);
|
|
472
|
-
gl.uniform2f(blurUniforms.direction, 1, 0);
|
|
473
|
-
gl.uniform1f(blurUniforms.radius, blurRadius);
|
|
474
|
-
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
475
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, processFramebuffers[1]);
|
|
476
|
-
gl.viewport(0, 0, width, height);
|
|
477
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
478
|
-
gl.bindTexture(gl.TEXTURE_2D, processTextures[0]);
|
|
479
|
-
gl.uniform1i(blurUniforms.texture, 0);
|
|
480
|
-
gl.uniform2f(blurUniforms.direction, 0, 1);
|
|
481
|
-
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
482
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
483
|
-
return processTextures[1];
|
|
484
|
-
}
|
|
485
|
-
function render(frame, mask) {
|
|
486
|
-
if (frame.codedWidth === 0 || mask.width === 0) {
|
|
651
|
+
let customBackgroundImage = emptyImageData;
|
|
652
|
+
function renderFrame(frame) {
|
|
653
|
+
if (frame.codedWidth === 0 || finalMaskTextures.length === 0) {
|
|
487
654
|
return;
|
|
488
655
|
}
|
|
489
656
|
const width = frame.displayWidth;
|
|
@@ -492,15 +659,33 @@ var setupWebGL = (canvas) => {
|
|
|
492
659
|
gl.bindTexture(gl.TEXTURE_2D, frameTexture);
|
|
493
660
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame);
|
|
494
661
|
let backgroundTexture = bgTexture;
|
|
495
|
-
if (
|
|
662
|
+
if (blurRadius) {
|
|
663
|
+
const downSampledFrameTexture = applyDownsampling(
|
|
664
|
+
gl,
|
|
665
|
+
frameTexture,
|
|
666
|
+
downSampler,
|
|
667
|
+
vertexBuffer,
|
|
668
|
+
bgBlurTextureWidth,
|
|
669
|
+
bgBlurTextureHeight
|
|
670
|
+
);
|
|
671
|
+
backgroundTexture = applyBlur(
|
|
672
|
+
gl,
|
|
673
|
+
downSampledFrameTexture,
|
|
674
|
+
bgBlurTextureWidth,
|
|
675
|
+
bgBlurTextureHeight,
|
|
676
|
+
blurRadius,
|
|
677
|
+
blurProgram,
|
|
678
|
+
blurUniforms,
|
|
679
|
+
vertexBuffer,
|
|
680
|
+
bgBlurFrameBuffers,
|
|
681
|
+
bgBlurTextures
|
|
682
|
+
);
|
|
683
|
+
} else {
|
|
496
684
|
gl.activeTexture(gl.TEXTURE0);
|
|
497
685
|
gl.bindTexture(gl.TEXTURE_2D, bgTexture);
|
|
498
686
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, customBackgroundImage);
|
|
499
687
|
backgroundTexture = bgTexture;
|
|
500
|
-
} else if (blurRadius) {
|
|
501
|
-
backgroundTexture = applyBlur(frameTexture, width, height);
|
|
502
688
|
}
|
|
503
|
-
const maskTexture = mask.getAsWebGLTexture();
|
|
504
689
|
gl.viewport(0, 0, width, height);
|
|
505
690
|
gl.clearColor(1, 1, 1, 1);
|
|
506
691
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
@@ -515,81 +700,89 @@ var setupWebGL = (canvas) => {
|
|
|
515
700
|
gl.bindTexture(gl.TEXTURE_2D, frameTexture);
|
|
516
701
|
gl.uniform1i(frameTextureLocation, 1);
|
|
517
702
|
gl.activeTexture(gl.TEXTURE2);
|
|
518
|
-
gl.bindTexture(gl.TEXTURE_2D,
|
|
703
|
+
gl.bindTexture(gl.TEXTURE_2D, finalMaskTextures[readMaskIndex]);
|
|
519
704
|
gl.uniform1i(maskTextureLocation, 2);
|
|
520
705
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
521
|
-
mask.close();
|
|
522
706
|
}
|
|
523
707
|
async function setBackgroundImage(image) {
|
|
524
|
-
customBackgroundImage =
|
|
708
|
+
customBackgroundImage = emptyImageData;
|
|
525
709
|
if (image) {
|
|
526
710
|
try {
|
|
527
|
-
const
|
|
528
|
-
const canvasHeight = canvas.height;
|
|
529
|
-
const imgAspect = image.width / image.height;
|
|
530
|
-
const canvasAspect = canvasWidth / canvasHeight;
|
|
531
|
-
let sx = 0;
|
|
532
|
-
let sy = 0;
|
|
533
|
-
let sWidth = image.width;
|
|
534
|
-
let sHeight = image.height;
|
|
535
|
-
if (imgAspect > canvasAspect) {
|
|
536
|
-
sWidth = Math.round(image.height * canvasAspect);
|
|
537
|
-
sx = Math.round((image.width - sWidth) / 2);
|
|
538
|
-
} else if (imgAspect < canvasAspect) {
|
|
539
|
-
sHeight = Math.round(image.width / canvasAspect);
|
|
540
|
-
sy = Math.round((image.height - sHeight) / 2);
|
|
541
|
-
}
|
|
542
|
-
const croppedImage = await createImageBitmap(image, sx, sy, sWidth, sHeight, {
|
|
543
|
-
resizeWidth: canvasWidth,
|
|
544
|
-
resizeHeight: canvasHeight,
|
|
545
|
-
resizeQuality: "medium"
|
|
546
|
-
});
|
|
711
|
+
const croppedImage = await resizeImageToCover(image, canvas.width, canvas.height);
|
|
547
712
|
customBackgroundImage = croppedImage;
|
|
548
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
549
|
-
gl.bindTexture(gl.TEXTURE_2D, bgTexture);
|
|
550
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, croppedImage);
|
|
551
713
|
} catch (error) {
|
|
552
|
-
console.error(
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
|
714
|
+
console.error(
|
|
715
|
+
"Error processing background image, falling back to black background:",
|
|
716
|
+
error
|
|
717
|
+
);
|
|
557
718
|
}
|
|
558
|
-
} else {
|
|
559
|
-
const emptyImage = new ImageData(2, 2);
|
|
560
|
-
emptyImage.data[0] = 0;
|
|
561
|
-
emptyImage.data[1] = 0;
|
|
562
|
-
emptyImage.data[2] = 0;
|
|
563
|
-
emptyImage.data[3] = 0;
|
|
564
|
-
gl.activeTexture(gl.TEXTURE0);
|
|
565
|
-
gl.bindTexture(gl.TEXTURE_2D, bgTexture);
|
|
566
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, emptyImage);
|
|
567
719
|
}
|
|
720
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
721
|
+
gl.bindTexture(gl.TEXTURE_2D, bgTexture);
|
|
722
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, customBackgroundImage);
|
|
568
723
|
}
|
|
569
724
|
function setBlurRadius(radius) {
|
|
570
|
-
blurRadius = radius;
|
|
725
|
+
blurRadius = radius ? Math.max(1, Math.floor(radius / downsampleFactor)) : null;
|
|
571
726
|
setBackgroundImage(null);
|
|
572
727
|
}
|
|
728
|
+
function updateMask(mask) {
|
|
729
|
+
const tempFramebuffers = [tempMaskFrameBuffer, finalMaskFrameBuffers[writeMaskIndex]];
|
|
730
|
+
const tempTextures = [tempMaskTexture, finalMaskTextures[writeMaskIndex]];
|
|
731
|
+
applyBlur(
|
|
732
|
+
gl,
|
|
733
|
+
mask,
|
|
734
|
+
canvas.width,
|
|
735
|
+
canvas.height,
|
|
736
|
+
maskBlurRadius || 1,
|
|
737
|
+
boxBlurProgram,
|
|
738
|
+
boxBlurUniforms,
|
|
739
|
+
vertexBuffer,
|
|
740
|
+
tempFramebuffers,
|
|
741
|
+
tempTextures
|
|
742
|
+
);
|
|
743
|
+
readMaskIndex = writeMaskIndex;
|
|
744
|
+
writeMaskIndex = 1 - writeMaskIndex;
|
|
745
|
+
}
|
|
573
746
|
function cleanup() {
|
|
574
747
|
gl.deleteProgram(compositeProgram);
|
|
575
748
|
gl.deleteProgram(blurProgram);
|
|
749
|
+
gl.deleteProgram(boxBlurProgram);
|
|
576
750
|
gl.deleteTexture(bgTexture);
|
|
577
751
|
gl.deleteTexture(frameTexture);
|
|
578
|
-
|
|
752
|
+
gl.deleteTexture(tempMaskTexture);
|
|
753
|
+
gl.deleteFramebuffer(tempMaskFrameBuffer);
|
|
754
|
+
for (const texture of bgBlurTextures) {
|
|
755
|
+
gl.deleteTexture(texture);
|
|
756
|
+
}
|
|
757
|
+
for (const framebuffer of bgBlurFrameBuffers) {
|
|
758
|
+
gl.deleteFramebuffer(framebuffer);
|
|
759
|
+
}
|
|
760
|
+
for (const texture of finalMaskTextures) {
|
|
579
761
|
gl.deleteTexture(texture);
|
|
580
762
|
}
|
|
581
|
-
for (const framebuffer of
|
|
763
|
+
for (const framebuffer of finalMaskFrameBuffers) {
|
|
582
764
|
gl.deleteFramebuffer(framebuffer);
|
|
583
765
|
}
|
|
584
766
|
gl.deleteBuffer(vertexBuffer);
|
|
767
|
+
if (blurredMaskTexture) {
|
|
768
|
+
gl.deleteTexture(blurredMaskTexture);
|
|
769
|
+
}
|
|
770
|
+
if (downSampler) {
|
|
771
|
+
gl.deleteTexture(downSampler.texture);
|
|
772
|
+
gl.deleteFramebuffer(downSampler.framebuffer);
|
|
773
|
+
gl.deleteProgram(downSampler.program);
|
|
774
|
+
}
|
|
585
775
|
if (customBackgroundImage) {
|
|
586
|
-
customBackgroundImage
|
|
587
|
-
|
|
776
|
+
if (customBackgroundImage instanceof ImageBitmap) {
|
|
777
|
+
customBackgroundImage.close();
|
|
778
|
+
}
|
|
779
|
+
customBackgroundImage = emptyImageData;
|
|
588
780
|
}
|
|
589
|
-
|
|
590
|
-
|
|
781
|
+
bgBlurTextures = [];
|
|
782
|
+
bgBlurFrameBuffers = [];
|
|
783
|
+
finalMaskTextures = [];
|
|
591
784
|
}
|
|
592
|
-
return {
|
|
785
|
+
return { renderFrame, updateMask, setBackgroundImage, setBlurRadius, cleanup };
|
|
593
786
|
};
|
|
594
787
|
|
|
595
788
|
// src/transformers/VideoTransformer.ts
|
|
@@ -640,6 +833,7 @@ var BackgroundProcessor = class extends VideoTransformer {
|
|
|
640
833
|
constructor(opts) {
|
|
641
834
|
super();
|
|
642
835
|
this.backgroundImage = null;
|
|
836
|
+
this.segmentationTimeMs = 0;
|
|
643
837
|
this.options = opts;
|
|
644
838
|
this.update(opts);
|
|
645
839
|
}
|
|
@@ -691,7 +885,7 @@ var BackgroundProcessor = class extends VideoTransformer {
|
|
|
691
885
|
(_a = this.gl) == null ? void 0 : _a.setBackgroundImage(imageData);
|
|
692
886
|
}
|
|
693
887
|
async transform(frame, controller) {
|
|
694
|
-
var _a;
|
|
888
|
+
var _a, _b;
|
|
695
889
|
try {
|
|
696
890
|
if (!(frame instanceof VideoFrame) || frame.codedWidth === 0 || frame.codedHeight === 0) {
|
|
697
891
|
console.debug("empty frame detected, ignoring");
|
|
@@ -701,37 +895,49 @@ var BackgroundProcessor = class extends VideoTransformer {
|
|
|
701
895
|
controller.enqueue(frame);
|
|
702
896
|
return;
|
|
703
897
|
}
|
|
898
|
+
const frameTimeMs = Date.now();
|
|
704
899
|
if (!this.canvas) {
|
|
705
900
|
throw TypeError("Canvas needs to be initialized first");
|
|
706
901
|
}
|
|
707
902
|
this.canvas.width = frame.displayWidth;
|
|
708
903
|
this.canvas.height = frame.displayHeight;
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
904
|
+
const segmentationPromise = new Promise((resolve, reject) => {
|
|
905
|
+
var _a2;
|
|
906
|
+
try {
|
|
907
|
+
let segmentationStartTimeMs = performance.now();
|
|
908
|
+
(_a2 = this.imageSegmenter) == null ? void 0 : _a2.segmentForVideo(frame, segmentationStartTimeMs, (result) => {
|
|
909
|
+
this.segmentationTimeMs = performance.now() - segmentationStartTimeMs;
|
|
910
|
+
this.segmentationResults = result;
|
|
911
|
+
this.updateMask(result.categoryMask);
|
|
912
|
+
result.close();
|
|
913
|
+
resolve();
|
|
718
914
|
});
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
processingTimeMs: performance.now() - startTimeMs,
|
|
722
|
-
segmentationTimeMs,
|
|
723
|
-
filterTimeMs
|
|
724
|
-
};
|
|
725
|
-
(_b = (_a2 = this.options).onFrameProcessed) == null ? void 0 : _b.call(_a2, stats);
|
|
726
|
-
controller.enqueue(newFrame);
|
|
727
|
-
} else {
|
|
728
|
-
controller.enqueue(frame);
|
|
915
|
+
} catch (e) {
|
|
916
|
+
reject(e);
|
|
729
917
|
}
|
|
730
|
-
frame.close();
|
|
731
918
|
});
|
|
919
|
+
const filterStartTimeMs = performance.now();
|
|
920
|
+
this.drawFrame(frame);
|
|
921
|
+
if (this.canvas && this.canvas.width > 0 && this.canvas.height > 0) {
|
|
922
|
+
const newFrame = new VideoFrame(this.canvas, {
|
|
923
|
+
timestamp: frame.timestamp || frameTimeMs
|
|
924
|
+
});
|
|
925
|
+
controller.enqueue(newFrame);
|
|
926
|
+
const filterTimeMs = performance.now() - filterStartTimeMs;
|
|
927
|
+
const stats = {
|
|
928
|
+
processingTimeMs: this.segmentationTimeMs + filterTimeMs,
|
|
929
|
+
segmentationTimeMs: this.segmentationTimeMs,
|
|
930
|
+
filterTimeMs
|
|
931
|
+
};
|
|
932
|
+
(_b = (_a = this.options).onFrameProcessed) == null ? void 0 : _b.call(_a, stats);
|
|
933
|
+
} else {
|
|
934
|
+
controller.enqueue(frame);
|
|
935
|
+
}
|
|
936
|
+
await segmentationPromise;
|
|
732
937
|
} catch (e) {
|
|
733
938
|
console.error("Error while processing frame: ", e);
|
|
734
|
-
|
|
939
|
+
} finally {
|
|
940
|
+
frame.close();
|
|
735
941
|
}
|
|
736
942
|
}
|
|
737
943
|
async update(opts) {
|
|
@@ -744,12 +950,16 @@ var BackgroundProcessor = class extends VideoTransformer {
|
|
|
744
950
|
}
|
|
745
951
|
}
|
|
746
952
|
async drawFrame(frame) {
|
|
747
|
-
|
|
953
|
+
var _a;
|
|
954
|
+
if (!this.gl)
|
|
748
955
|
return;
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
956
|
+
(_a = this.gl) == null ? void 0 : _a.renderFrame(frame);
|
|
957
|
+
}
|
|
958
|
+
async updateMask(mask) {
|
|
959
|
+
var _a;
|
|
960
|
+
if (!mask)
|
|
961
|
+
return;
|
|
962
|
+
(_a = this.gl) == null ? void 0 : _a.updateMask(mask.getAsWebGLTexture());
|
|
753
963
|
}
|
|
754
964
|
};
|
|
755
965
|
|
|
@@ -797,17 +1007,14 @@ var BackgroundProcessor2 = (options, name = "background-processor") => {
|
|
|
797
1007
|
onFrameProcessed,
|
|
798
1008
|
...processorOpts
|
|
799
1009
|
} = options;
|
|
800
|
-
const
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
name,
|
|
809
|
-
processorOpts
|
|
810
|
-
);
|
|
1010
|
+
const transformer = new BackgroundProcessor({
|
|
1011
|
+
blurRadius,
|
|
1012
|
+
imagePath,
|
|
1013
|
+
segmenterOptions,
|
|
1014
|
+
assetPaths,
|
|
1015
|
+
onFrameProcessed
|
|
1016
|
+
});
|
|
1017
|
+
const processor = new ProcessorWrapper(transformer, name, processorOpts);
|
|
811
1018
|
return processor;
|
|
812
1019
|
};
|
|
813
1020
|
|