@stream-io/video-filters-web 0.8.6 → 0.8.7
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/CHANGELOG.md +6 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/src/BaseVideoProcessor.js +107 -0
- package/dist/esm/src/BaseVideoProcessor.js.map +1 -0
- package/dist/esm/src/FallbackGenerator.js +58 -0
- package/dist/esm/src/FallbackGenerator.js.map +1 -0
- package/dist/esm/src/FallbackProcessor.js +89 -0
- package/dist/esm/src/FallbackProcessor.js.map +1 -0
- package/dist/esm/src/FullScreenBlur.js +41 -0
- package/dist/esm/src/FullScreenBlur.js.map +1 -0
- package/dist/esm/src/FullScreenBlurRenderer.js +276 -0
- package/dist/esm/src/FullScreenBlurRenderer.js.map +1 -0
- package/dist/esm/src/VirtualBackground.js +143 -0
- package/dist/esm/src/VirtualBackground.js.map +1 -0
- package/dist/esm/src/WebGLRenderer.js +723 -0
- package/dist/esm/src/WebGLRenderer.js.map +1 -0
- package/dist/esm/src/compatibility.js +48 -0
- package/dist/esm/src/compatibility.js.map +1 -0
- package/dist/esm/src/legacy/createRenderer.js +33 -0
- package/dist/esm/src/legacy/createRenderer.js.map +1 -0
- package/dist/esm/src/legacy/helpers/webglHelper.js +94 -0
- package/dist/esm/src/legacy/helpers/webglHelper.js.map +1 -0
- package/dist/esm/src/legacy/segmentation.js +14 -0
- package/dist/esm/src/legacy/segmentation.js.map +1 -0
- package/dist/esm/src/legacy/tflite-simd.js +728 -0
- package/dist/esm/src/legacy/tflite-simd.js.map +1 -0
- package/dist/esm/src/legacy/tflite.js +31 -0
- package/dist/esm/src/legacy/tflite.js.map +1 -0
- package/dist/esm/src/legacy/webgl2/backgroundBlurStage.js +202 -0
- package/dist/esm/src/legacy/webgl2/backgroundBlurStage.js.map +1 -0
- package/dist/esm/src/legacy/webgl2/backgroundImageStage.js +157 -0
- package/dist/esm/src/legacy/webgl2/backgroundImageStage.js.map +1 -0
- package/dist/esm/src/legacy/webgl2/jointBilateralFilterStage.js +113 -0
- package/dist/esm/src/legacy/webgl2/jointBilateralFilterStage.js.map +1 -0
- package/dist/esm/src/legacy/webgl2/resizingStage.js +57 -0
- package/dist/esm/src/legacy/webgl2/resizingStage.js.map +1 -0
- package/dist/esm/src/legacy/webgl2/softmaxStage.js +51 -0
- package/dist/esm/src/legacy/webgl2/softmaxStage.js.map +1 -0
- package/dist/esm/src/legacy/webgl2/webgl2Pipeline.js +105 -0
- package/dist/esm/src/legacy/webgl2/webgl2Pipeline.js.map +1 -0
- package/dist/esm/src/mediapipe.js +16 -0
- package/dist/esm/src/mediapipe.js.map +1 -0
- package/dist/esm/src/types.js +11 -0
- package/dist/esm/src/types.js.map +1 -0
- package/dist/esm/src/version.js +5 -0
- package/dist/esm/src/version.js.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/package.json +3 -3
- package/dist/index.es.js +0 -3022
- package/dist/index.es.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FullScreenBlurRenderer.js","sources":["../../../../../src/FullScreenBlurRenderer.ts"],"sourcesContent":["/**\n * Simple WebGL renderer for full-screen Gaussian blur.\n * Uses a two-pass separable Gaussian blur (horizontal then vertical).\n * Optimized for moderation use cases by blurring at reduced resolution (15% scale)\n * and upscaling back to full resolution for output.\n */\nexport class FullScreenBlurRenderer {\n readonly canvas: OffscreenCanvas;\n readonly gl: WebGL2RenderingContext;\n\n readonly blurProgramHandle: WebGLProgram;\n readonly blurLocations: {\n positionLocation: number;\n texCoordLocation: number;\n imageLocation: WebGLUniformLocation | null;\n texelSizeLocation: WebGLUniformLocation | null;\n directionLocation: WebGLUniformLocation | null;\n weightsLocation: WebGLUniformLocation | null;\n };\n\n readonly passthroughProgramHandle: WebGLProgram;\n readonly passthroughLocations: {\n positionLocation: number;\n texCoordLocation: number;\n imageLocation: WebGLUniformLocation | null;\n };\n\n readonly positionBuffer: WebGLBuffer | null;\n readonly texCoordBuffer: WebGLBuffer | null;\n\n readonly pingTexture: WebGLTexture | null;\n readonly pongTexture: WebGLTexture | null;\n readonly pingFbo: WebGLFramebuffer | null;\n readonly pongFbo: WebGLFramebuffer | null;\n\n private inputTexture: WebGLTexture | null = null;\n private isRunning = false;\n\n private targetWidth = 0;\n private targetHeight = 0;\n\n private weightCache = new Map<number, Float32Array>();\n\n constructor(canvas: OffscreenCanvas) {\n this.canvas = canvas;\n\n const gl = canvas.getContext('webgl2', {\n alpha: false,\n antialias: false,\n desynchronized: true,\n });\n\n if (!gl) throw new Error('WebGL2 not supported');\n this.gl = gl;\n\n const vertexShaderSource = `#version 300 es\n precision highp float;\n in vec2 a_position;\n in vec2 a_texCoord;\n out vec2 v_texCoord;\n void main() {\n v_texCoord = a_texCoord;\n gl_Position = vec4(a_position, 0.0, 1.0);\n }\n `;\n\n const fragmentShaderSource = `#version 300 es\n precision highp float;\n in vec2 v_texCoord;\n out vec4 outColor;\n uniform sampler2D u_image;\n uniform vec2 u_texelSize;\n uniform vec2 u_direction;\n uniform float u_weights[25];\n void main() {\n vec4 color = vec4(0.0);\n for (int i = -12; i <= 12; i++) {\n float w = u_weights[i + 12];\n if (w == 0.0) continue;\n vec2 offset = float(i) * u_direction * u_texelSize;\n color += w * texture(u_image, v_texCoord + offset);\n }\n outColor = color;\n }\n `;\n\n this.blurProgramHandle = this.createAndLinkProgram(\n vertexShaderSource,\n fragmentShaderSource,\n );\n\n const passthroughFragmentShaderSource = `#version 300 es\n precision highp float;\n in vec2 v_texCoord;\n out vec4 outColor;\n uniform sampler2D u_image;\n void main() {\n outColor = texture(u_image, v_texCoord);\n }\n `;\n\n this.passthroughProgramHandle = this.createAndLinkProgram(\n vertexShaderSource,\n passthroughFragmentShaderSource,\n );\n\n const blurProgram = this.blurProgramHandle;\n const passthroughProgram = this.passthroughProgramHandle;\n\n this.blurLocations = {\n positionLocation: gl.getAttribLocation(blurProgram, 'a_position'),\n texCoordLocation: gl.getAttribLocation(blurProgram, 'a_texCoord'),\n imageLocation: gl.getUniformLocation(blurProgram, 'u_image'),\n texelSizeLocation: gl.getUniformLocation(blurProgram, 'u_texelSize'),\n directionLocation: gl.getUniformLocation(blurProgram, 'u_direction'),\n weightsLocation: gl.getUniformLocation(blurProgram, 'u_weights'),\n };\n\n this.passthroughLocations = {\n positionLocation: gl.getAttribLocation(passthroughProgram, 'a_position'),\n texCoordLocation: gl.getAttribLocation(passthroughProgram, 'a_texCoord'),\n imageLocation: gl.getUniformLocation(passthroughProgram, 'u_image'),\n };\n\n this.positionBuffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);\n gl.bufferData(\n gl.ARRAY_BUFFER,\n new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n gl.STATIC_DRAW,\n );\n\n this.texCoordBuffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);\n gl.bufferData(\n gl.ARRAY_BUFFER,\n new Float32Array([0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0]),\n gl.STATIC_DRAW,\n );\n\n const createTexture2D = () => {\n const tex = gl.createTexture();\n if (!tex) throw new Error('Failed to create texture');\n gl.bindTexture(gl.TEXTURE_2D, tex);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.bindTexture(gl.TEXTURE_2D, null);\n return tex;\n };\n\n const createFramebufferForTexture = (tex: WebGLTexture) => {\n const fb = gl.createFramebuffer();\n if (!fb) throw new Error('Failed to create framebuffer');\n gl.bindFramebuffer(gl.FRAMEBUFFER, fb);\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n gl.COLOR_ATTACHMENT0,\n gl.TEXTURE_2D,\n tex,\n 0,\n );\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n return fb;\n };\n\n this.pingTexture = createTexture2D();\n this.pongTexture = createTexture2D();\n this.pingFbo = createFramebufferForTexture(this.pingTexture);\n this.pongFbo = createFramebufferForTexture(this.pongTexture);\n\n this.inputTexture = createTexture2D();\n\n gl.useProgram(blurProgram);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);\n gl.enableVertexAttribArray(this.blurLocations.positionLocation);\n gl.vertexAttribPointer(\n this.blurLocations.positionLocation,\n 2,\n gl.FLOAT,\n false,\n 0,\n 0,\n );\n\n gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);\n gl.enableVertexAttribArray(this.blurLocations.texCoordLocation);\n gl.vertexAttribPointer(\n this.blurLocations.texCoordLocation,\n 2,\n gl.FLOAT,\n false,\n 0,\n 0,\n );\n\n if (this.blurLocations.imageLocation) {\n gl.uniform1i(this.blurLocations.imageLocation, 0);\n }\n\n this.isRunning = true;\n }\n\n private createAndLinkProgram(\n vsSource: string,\n fsSource: string,\n ): WebGLProgram {\n const gl = this.gl;\n const vs = this.createShader(gl.VERTEX_SHADER, vsSource);\n const fs = this.createShader(gl.FRAGMENT_SHADER, fsSource);\n\n const prog = gl.createProgram();\n if (!prog) throw new Error('Failed to create program');\n gl.attachShader(prog, vs);\n gl.attachShader(prog, fs);\n gl.linkProgram(prog);\n\n if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {\n throw new Error('Shader link failed: ' + gl.getProgramInfoLog(prog));\n }\n\n gl.deleteShader(vs);\n gl.deleteShader(fs);\n return prog;\n }\n\n private createShader(type: number, source: string): WebGLShader {\n const gl = this.gl;\n const shader = gl.createShader(type);\n if (!shader) throw new Error('Failed to create shader');\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n throw new Error('Shader compile failed: ' + gl.getShaderInfoLog(shader));\n }\n return shader;\n }\n\n private getGaussianWeights(radius: number): Float32Array {\n const r = Math.max(0, Math.min(radius | 0, 12));\n\n const cached = this.weightCache.get(r);\n if (cached) return cached;\n\n const weights = new Float32Array(25);\n\n if (r === 0) {\n weights[12] = 1.0;\n this.weightCache.set(r, weights);\n return weights;\n }\n\n const sigma = r * 0.6;\n let sum = 0;\n\n for (let i = -r; i <= r; i++) {\n const w = Math.exp(-(i * i) / (2 * sigma * sigma));\n weights[i + 12] = w;\n sum += w;\n }\n\n for (let i = -r; i <= r; i++) {\n weights[i + 12] /= sum;\n }\n\n this.weightCache.set(r, weights);\n return weights;\n }\n\n public render(frame: VideoFrame, radius: number): void {\n if (!this.isRunning) return;\n\n const gl = this.gl;\n\n const width = frame.displayWidth;\n const height = frame.displayHeight;\n\n if (!width || !height) return;\n\n if (this.canvas.width !== width || this.canvas.height !== height) {\n this.canvas.width = width;\n this.canvas.height = height;\n }\n\n const scale = 0.15;\n const scaledWidth = Math.max(1, Math.floor(width * scale));\n const scaledHeight = Math.max(1, Math.floor(height * scale));\n\n if (\n scaledWidth !== this.targetWidth ||\n scaledHeight !== this.targetHeight\n ) {\n this.targetWidth = scaledWidth;\n this.targetHeight = scaledHeight;\n\n gl.bindTexture(gl.TEXTURE_2D, this.pingTexture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n scaledWidth,\n scaledHeight,\n 0,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n null,\n );\n\n gl.bindTexture(gl.TEXTURE_2D, this.pongTexture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n scaledWidth,\n scaledHeight,\n 0,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n null,\n );\n\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, this.inputTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame);\n\n gl.useProgram(this.blurProgramHandle);\n\n if (this.blurLocations.texelSizeLocation) {\n gl.uniform2f(\n this.blurLocations.texelSizeLocation,\n 1.0 / scaledWidth,\n 1.0 / scaledHeight,\n );\n }\n\n const weights = this.getGaussianWeights(radius);\n if (this.blurLocations.weightsLocation) {\n gl.uniform1fv(this.blurLocations.weightsLocation, weights);\n }\n\n gl.viewport(0, 0, scaledWidth, scaledHeight);\n gl.bindFramebuffer(gl.FRAMEBUFFER, this.pingFbo);\n gl.bindTexture(gl.TEXTURE_2D, this.inputTexture);\n if (this.blurLocations.directionLocation) {\n gl.uniform2f(this.blurLocations.directionLocation, 1.0, 0.0);\n }\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, this.pongFbo);\n gl.bindTexture(gl.TEXTURE_2D, this.pingTexture);\n if (this.blurLocations.directionLocation) {\n gl.uniform2f(this.blurLocations.directionLocation, 0.0, 1.0);\n }\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n gl.viewport(0, 0, width, height);\n gl.useProgram(this.passthroughProgramHandle);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);\n gl.enableVertexAttribArray(this.passthroughLocations.positionLocation);\n gl.vertexAttribPointer(\n this.passthroughLocations.positionLocation,\n 2,\n gl.FLOAT,\n false,\n 0,\n 0,\n );\n\n gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);\n gl.enableVertexAttribArray(this.passthroughLocations.texCoordLocation);\n gl.vertexAttribPointer(\n this.passthroughLocations.texCoordLocation,\n 2,\n gl.FLOAT,\n false,\n 0,\n 0,\n );\n\n gl.bindTexture(gl.TEXTURE_2D, this.pongTexture);\n if (this.passthroughLocations.imageLocation) {\n gl.uniform1i(this.passthroughLocations.imageLocation, 0);\n }\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n }\n\n public close(): void {\n if (!this.isRunning) return;\n this.isRunning = false;\n const gl = this.gl;\n\n if (this.pingFbo) gl.deleteFramebuffer(this.pingFbo);\n if (this.pongFbo) gl.deleteFramebuffer(this.pongFbo);\n if (this.pingTexture) gl.deleteTexture(this.pingTexture);\n if (this.pongTexture) gl.deleteTexture(this.pongTexture);\n if (this.inputTexture) gl.deleteTexture(this.inputTexture);\n if (this.positionBuffer) gl.deleteBuffer(this.positionBuffer);\n if (this.texCoordBuffer) gl.deleteBuffer(this.texCoordBuffer);\n\n gl.deleteProgram(this.blurProgramHandle);\n gl.deleteProgram(this.passthroughProgramHandle);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { BACKGROUND_BLUR_MAP } from './types.js';
|
|
2
|
+
import { FilesetResolver, ImageSegmenter } from '@mediapipe/tasks-vision';
|
|
3
|
+
import { WebGLRenderer } from './WebGLRenderer.js';
|
|
4
|
+
import { packageName, version } from './version.js';
|
|
5
|
+
import { BaseVideoProcessor } from './BaseVideoProcessor.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Wraps a video MediaStreamTrack in a real-time processing pipeline.
|
|
9
|
+
* Incoming frames are processed through a transformer and re-emitted
|
|
10
|
+
* on a new MediaStreamVideoTrack for downstream consumption.
|
|
11
|
+
*/
|
|
12
|
+
class VirtualBackground extends BaseVideoProcessor {
|
|
13
|
+
options;
|
|
14
|
+
segmenter = null;
|
|
15
|
+
isSegmenterReady = false;
|
|
16
|
+
webGlRenderer;
|
|
17
|
+
opts;
|
|
18
|
+
latestCategoryMask = undefined;
|
|
19
|
+
latestConfidenceMask = undefined;
|
|
20
|
+
lastFrameTime = -1;
|
|
21
|
+
constructor(track, options = {}, hooks = {}) {
|
|
22
|
+
super(track, hooks);
|
|
23
|
+
this.options = options;
|
|
24
|
+
}
|
|
25
|
+
async initialize() {
|
|
26
|
+
this.webGlRenderer = new WebGLRenderer(this.canvas);
|
|
27
|
+
await this.initializeSegmenter();
|
|
28
|
+
}
|
|
29
|
+
async initializeSegmenter() {
|
|
30
|
+
try {
|
|
31
|
+
this.opts = await this.initializeSegmenterOptions();
|
|
32
|
+
const basePath = this.options.basePath ||
|
|
33
|
+
`https://unpkg.com/${packageName}@${version}/mediapipe`;
|
|
34
|
+
const model = this.options.modelPath ||
|
|
35
|
+
`${basePath}/models/selfie_segmenter_landscape.tflite`;
|
|
36
|
+
const fileset = await FilesetResolver.forVisionTasks(`${basePath}/wasm`);
|
|
37
|
+
this.segmenter = await ImageSegmenter.createFromOptions(fileset, {
|
|
38
|
+
baseOptions: { modelAssetPath: model, delegate: 'GPU' },
|
|
39
|
+
runningMode: 'VIDEO',
|
|
40
|
+
outputCategoryMask: true,
|
|
41
|
+
outputConfidenceMasks: true,
|
|
42
|
+
canvas: this.canvas,
|
|
43
|
+
});
|
|
44
|
+
this.isSegmenterReady = true;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
this.isSegmenterReady = false;
|
|
48
|
+
this.hooks.onError?.(error);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async transform(frame) {
|
|
53
|
+
const currentTime = frame.timestamp;
|
|
54
|
+
const hasNewFrame = currentTime - this.lastFrameTime > 1_000;
|
|
55
|
+
this.lastFrameTime = currentTime;
|
|
56
|
+
if (hasNewFrame && this.isSegmenterReady && this.segmenter) {
|
|
57
|
+
const start = performance.now();
|
|
58
|
+
await this.runSegmentation(frame);
|
|
59
|
+
this.webGlRenderer.render(frame, this.opts, this.latestCategoryMask, this.latestConfidenceMask);
|
|
60
|
+
this.updateStats(performance.now() - start);
|
|
61
|
+
}
|
|
62
|
+
return new VideoFrame(this.canvas, { timestamp: frame.timestamp });
|
|
63
|
+
}
|
|
64
|
+
async runSegmentation(frame) {
|
|
65
|
+
if (!this.segmenter)
|
|
66
|
+
return;
|
|
67
|
+
return new Promise((resolve) => {
|
|
68
|
+
const timestamp = Math.floor(performance.now());
|
|
69
|
+
this.segmenter.segmentForVideo(frame, timestamp, (result) => {
|
|
70
|
+
try {
|
|
71
|
+
this.latestCategoryMask = result.categoryMask?.getAsWebGLTexture();
|
|
72
|
+
this.latestConfidenceMask =
|
|
73
|
+
result.confidenceMasks?.[0]?.getAsWebGLTexture();
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error('[virtual-background] segmentation error:', err);
|
|
77
|
+
this.hooks.onError?.(err);
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
result.close();
|
|
81
|
+
resolve();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
async initializeSegmenterOptions() {
|
|
87
|
+
const isSelfieMode = this.options.modelPath
|
|
88
|
+
? this.options.modelPath.includes('selfie_segmenter')
|
|
89
|
+
: true;
|
|
90
|
+
if (this.options.backgroundFilter === 'image') {
|
|
91
|
+
const source = await this.loadBackground(this.options.backgroundImage);
|
|
92
|
+
return {
|
|
93
|
+
backgroundSource: source,
|
|
94
|
+
bgBlur: 0,
|
|
95
|
+
bgBlurRadius: 0,
|
|
96
|
+
isSelfieMode,
|
|
97
|
+
segmentationOptions: this.options.segmentationOptions,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const blurLevel = this.options.backgroundBlurLevel;
|
|
101
|
+
const strength = typeof blurLevel === 'string'
|
|
102
|
+
? BACKGROUND_BLUR_MAP[blurLevel]
|
|
103
|
+
: Math.round(blurLevel ?? 5);
|
|
104
|
+
return {
|
|
105
|
+
backgroundSource: undefined,
|
|
106
|
+
bgBlur: Math.min(strength * 1.5, 20),
|
|
107
|
+
bgBlurRadius: Math.min(strength, 10),
|
|
108
|
+
isSelfieMode,
|
|
109
|
+
segmentationOptions: this.options.segmentationOptions,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async loadBackground(url) {
|
|
113
|
+
if (!url)
|
|
114
|
+
return null;
|
|
115
|
+
const result = await fetch(url, { signal: this.abortController.signal });
|
|
116
|
+
if (!result.ok) {
|
|
117
|
+
throw new Error(`[virtual-background] Failed to load background image: ${result.status} ${result.statusText}`);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
type: 'image',
|
|
121
|
+
media: await createImageBitmap(await result.blob()),
|
|
122
|
+
url,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
onFlush() {
|
|
126
|
+
this.destroySegmenter();
|
|
127
|
+
}
|
|
128
|
+
onStop() {
|
|
129
|
+
this.webGlRenderer?.close();
|
|
130
|
+
this.destroySegmenter();
|
|
131
|
+
}
|
|
132
|
+
destroySegmenter() {
|
|
133
|
+
this.segmenter?.close();
|
|
134
|
+
this.segmenter = null;
|
|
135
|
+
this.isSegmenterReady = false;
|
|
136
|
+
}
|
|
137
|
+
get processorName() {
|
|
138
|
+
return 'background-processor';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { VirtualBackground };
|
|
143
|
+
//# sourceMappingURL=VirtualBackground.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VirtualBackground.js","sources":["../../../../../src/VirtualBackground.ts"],"sourcesContent":["import {\n BACKGROUND_BLUR_MAP,\n BackgroundOptions,\n SegmenterOptions,\n VideoTrackProcessorHooks,\n} from './types';\nimport { FilesetResolver, ImageSegmenter } from '@mediapipe/tasks-vision';\nimport { WebGLRenderer } from './WebGLRenderer';\nimport { packageName, version } from './version';\nimport { BaseVideoProcessor } from './BaseVideoProcessor';\n\n/**\n * Wraps a video MediaStreamTrack in a real-time processing pipeline.\n * Incoming frames are processed through a transformer and re-emitted\n * on a new MediaStreamVideoTrack for downstream consumption.\n */\nexport class VirtualBackground extends BaseVideoProcessor {\n private segmenter: ImageSegmenter | null = null;\n private isSegmenterReady = false;\n private webGlRenderer!: WebGLRenderer;\n\n private opts!: SegmenterOptions;\n\n private latestCategoryMask: WebGLTexture | undefined = undefined;\n private latestConfidenceMask: WebGLTexture | undefined = undefined;\n private lastFrameTime = -1;\n\n constructor(\n track: MediaStreamVideoTrack,\n private readonly options: BackgroundOptions = {},\n hooks: VideoTrackProcessorHooks = {},\n ) {\n super(track, hooks);\n }\n\n protected async initialize(): Promise<void> {\n this.webGlRenderer = new WebGLRenderer(this.canvas);\n\n await this.initializeSegmenter();\n }\n\n private async initializeSegmenter() {\n try {\n this.opts = await this.initializeSegmenterOptions();\n\n const basePath =\n this.options.basePath ||\n `https://unpkg.com/${packageName}@${version}/mediapipe`;\n\n const model =\n this.options.modelPath ||\n `${basePath}/models/selfie_segmenter_landscape.tflite`;\n\n const fileset = await FilesetResolver.forVisionTasks(`${basePath}/wasm`);\n\n this.segmenter = await ImageSegmenter.createFromOptions(fileset, {\n baseOptions: { modelAssetPath: model, delegate: 'GPU' },\n runningMode: 'VIDEO',\n outputCategoryMask: true,\n outputConfidenceMasks: true,\n canvas: this.canvas,\n });\n\n this.isSegmenterReady = true;\n } catch (error) {\n this.isSegmenterReady = false;\n this.hooks.onError?.(error);\n throw error;\n }\n }\n\n protected async transform(frame: VideoFrame): Promise<VideoFrame> {\n const currentTime = frame.timestamp;\n const hasNewFrame = currentTime - this.lastFrameTime > 1_000;\n this.lastFrameTime = currentTime;\n\n if (hasNewFrame && this.isSegmenterReady && this.segmenter) {\n const start = performance.now();\n\n await this.runSegmentation(frame);\n\n this.webGlRenderer.render(\n frame,\n this.opts,\n this.latestCategoryMask,\n this.latestConfidenceMask,\n );\n\n this.updateStats(performance.now() - start);\n }\n\n return new VideoFrame(this.canvas, { timestamp: frame.timestamp });\n }\n\n private async runSegmentation(frame: VideoFrame): Promise<void> {\n if (!this.segmenter) return;\n\n return new Promise<void>((resolve) => {\n const timestamp = Math.floor(performance.now());\n this.segmenter!.segmentForVideo(frame, timestamp, (result) => {\n try {\n this.latestCategoryMask = result.categoryMask?.getAsWebGLTexture();\n this.latestConfidenceMask =\n result.confidenceMasks?.[0]?.getAsWebGLTexture();\n } catch (err) {\n console.error('[virtual-background] segmentation error:', err);\n this.hooks.onError?.(err);\n } finally {\n result.close();\n resolve();\n }\n });\n });\n }\n\n private async initializeSegmenterOptions(): Promise<SegmenterOptions> {\n const isSelfieMode = this.options.modelPath\n ? this.options.modelPath.includes('selfie_segmenter')\n : true;\n\n if (this.options.backgroundFilter === 'image') {\n const source = await this.loadBackground(this.options.backgroundImage);\n return {\n backgroundSource: source,\n bgBlur: 0,\n bgBlurRadius: 0,\n isSelfieMode,\n segmentationOptions: this.options.segmentationOptions,\n };\n }\n\n const blurLevel = this.options.backgroundBlurLevel;\n const strength =\n typeof blurLevel === 'string'\n ? BACKGROUND_BLUR_MAP[blurLevel]\n : Math.round(blurLevel ?? 5);\n\n return {\n backgroundSource: undefined,\n bgBlur: Math.min(strength * 1.5, 20),\n bgBlurRadius: Math.min(strength, 10),\n isSelfieMode,\n segmentationOptions: this.options.segmentationOptions,\n };\n }\n\n private async loadBackground(url?: string) {\n if (!url) return null;\n const result = await fetch(url, { signal: this.abortController.signal });\n if (!result.ok) {\n throw new Error(\n `[virtual-background] Failed to load background image: ${result.status} ${result.statusText}`,\n );\n }\n\n return {\n type: 'image',\n media: await createImageBitmap(await result.blob()),\n url,\n };\n }\n\n protected onFlush(): void {\n this.destroySegmenter();\n }\n\n protected onStop(): void {\n this.webGlRenderer?.close();\n this.destroySegmenter();\n }\n\n private destroySegmenter() {\n this.segmenter?.close();\n this.segmenter = null;\n this.isSegmenterReady = false;\n }\n\n protected get processorName() {\n return 'background-processor';\n }\n}\n"],"names":[],"mappings":"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"}
|