@100mslive/hms-virtual-background 1.13.25-alpha.0 → 1.13.25-alpha.10
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 +237 -7
- package/dist/cjs/HMSEffectsPlugin.js +1 -1
- package/dist/cjs/HMSEffectsPlugin.js.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +2 -2
- package/dist/constants.d.ts +1 -1
- package/dist/esm/HMSEffectsPlugin.js +1 -1
- package/dist/esm/HMSEffectsPlugin.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +2 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,13 +1,243 @@
|
|
|
1
|
-
|
|
1
|
+
# Virtual Background with Effects SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/100mslive/web-sdks/actions/workflows/lint-test-build.yml)
|
|
4
|
+
[](https://bundlephobia.com/result?p=@100mslive/hms-virtual-background)
|
|
5
|
+
[](https://www.100ms.live/)
|
|
6
|
+

|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
Virtual background plugin helps in customising one’s background. The customising options are blurring the background or replacing it with a static image. This guide provides an overview of usage of the virtual background plugin of 100ms.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
## Pre-requisites
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
Get the 100ms VirtualBackground Package** (Supported since version 1.11.28)
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
```bash section=GetHMSVirtualBackgroundPackage sectionIndex=1
|
|
15
|
+
npm install --save @100mslive/hms-virtual-background@latest
|
|
16
|
+
```
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
The following features are currently supported under the `HMSEffectsPlugin` class:
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
/**
|
|
24
|
+
* Sets the blur intensity.
|
|
25
|
+
* @param {number} blur - The blur intensity, ranging from 0 to 1.
|
|
26
|
+
* @returns {void}
|
|
27
|
+
*/
|
|
28
|
+
setBlur(blur) {}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Sets the virtual background using the provided media URL.
|
|
32
|
+
* @param {HMSEffectsBackground} url - The media URL to set as the virtual background.
|
|
33
|
+
* Alternatively, the background image can be downloaded beforehand and passed to setBackground as objectURL
|
|
34
|
+
* @returns {void}
|
|
35
|
+
*/
|
|
36
|
+
setBackground(url) {}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Retrieves the name of the plugin.
|
|
40
|
+
* @returns {string} The name of the plugin, 'HMSEffects'.
|
|
41
|
+
*/
|
|
42
|
+
getName() {}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Retrieves the currently enabled background type or media URL.
|
|
46
|
+
* @returns {string|MediaStream|MediaStreamTrack|HTMLVideoElement} The background type or media URL.
|
|
47
|
+
*/
|
|
48
|
+
getBackground() {}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Sets the preset quality of the virtual background.
|
|
52
|
+
* Options: "balanced" | "quality"
|
|
53
|
+
* The 'quality' preset has a higher CPU usage than the 'balanced' preset which is the default
|
|
54
|
+
* @param {string} preset - The preset quality to set.
|
|
55
|
+
* @returns {Promise<void>}
|
|
56
|
+
*/
|
|
57
|
+
setPreset(preset) {}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Retrieves the active preset quality of the virtual background.
|
|
61
|
+
* @returns {string} The active preset quality.
|
|
62
|
+
*/
|
|
63
|
+
getPreset() {}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Clears all applied filters.
|
|
67
|
+
* @returns {void}
|
|
68
|
+
*/
|
|
69
|
+
removeEffects() {}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Stops the plugin.
|
|
73
|
+
* @returns {void}
|
|
74
|
+
*/
|
|
75
|
+
stop() {}
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Callbacks supported by the plugin:
|
|
80
|
+
|
|
81
|
+
On initialization, after the required resources are downloaded by the plugin:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
const effectsPlugin = new HMSEffectsPlugin(<key>, () => console.log("Plugin initialised"));
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
On resolution change (on device rotation or when the video aspect ratio changes):
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
effectsPlugin.onResolutionChange = (width: number, height: number) => {
|
|
92
|
+
console.log(`Resolution changed to ${width}x${height}`)
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Instantiate Virtual Background
|
|
97
|
+
|
|
98
|
+
The SDK key for effects is needed to instantiate the `HMSEffectsPlugin` class:
|
|
99
|
+
|
|
100
|
+
```jsx
|
|
101
|
+
const effectsKey = useHMSStore(selectEffectsKey);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
It is recommended to initialise the object in a separate file to prevent multiple initialisations on re-renders and keep the UI level code independent of internal calls by the SDK.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
import { HMSEffectsPlugin, HMSVirtualBackgroundTypes } from '@100mslive/hms-virtual-background';
|
|
109
|
+
|
|
110
|
+
export class VBPlugin {
|
|
111
|
+
private effectsPlugin?: HMSEffectsPlugin | undefined;
|
|
112
|
+
|
|
113
|
+
initialisePlugin = (effectsSDKKey?: string) => {
|
|
114
|
+
if (this.getVBObject()) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (effectsSDKKey) {
|
|
118
|
+
this.effectsPlugin = new HMSEffectsPlugin(effectsSDKKey);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
getBackground = () => {
|
|
123
|
+
return this.effectsPlugin?.getBackground();
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
getBlurAmount = () => {
|
|
127
|
+
return this.effectsPlugin?.getBlurAmount();
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
getVBObject = () => {
|
|
131
|
+
return this.effectsPlugin;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
getName = () => {
|
|
135
|
+
return this.effectsPlugin?.getName();
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
setBlur = async (blurPower: number) => {
|
|
139
|
+
this.effectsPlugin?.setBlur(blurPower);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
setBackground = async (mediaURL: string) => {
|
|
143
|
+
this.effectsPlugin?.setBackground(mediaURL);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
setPreset = (preset: string) => {
|
|
147
|
+
this.effectsPlugin.setPreset(preset);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
getPreset = () => {
|
|
151
|
+
return this.effectsPlugin?.getPreset() || '';
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
removeEffects = async () => {
|
|
155
|
+
this.effectsPlugin?.removeEffects();
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
reset = () => {
|
|
159
|
+
this.effectsPlugin = undefined;
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export const VBHandler = new VBPlugin();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Building the UI
|
|
167
|
+
|
|
168
|
+
The following snippet illustrates how to add the plugin to the video and manage the UI state to preserve configuration:
|
|
169
|
+
|
|
170
|
+
```jsx
|
|
171
|
+
import {
|
|
172
|
+
selectEffectsKey,
|
|
173
|
+
selectIsLocalVideoPluginPresent
|
|
174
|
+
selectLocalVideoTrackID,
|
|
175
|
+
useHMSStore,
|
|
176
|
+
} from '@100mslive/react-sdk';
|
|
177
|
+
import {
|
|
178
|
+
HMSEffectsPlugin,
|
|
179
|
+
HMSVirtualBackgroundTypes
|
|
180
|
+
} from '@100mslive/hms-virtual-background';
|
|
181
|
+
import { VBHandler } from './VBHandler';
|
|
182
|
+
|
|
183
|
+
export const VirtualBackgroundPicker = () => {
|
|
184
|
+
const hmsActions = useHMSActions();
|
|
185
|
+
// Get the effects SDK key here
|
|
186
|
+
const effectsKey = useHMSStore(selectEffectsKey);
|
|
187
|
+
const trackId = useHMSStore(selectLocalVideoTrackID);
|
|
188
|
+
const isPluginAdded = useHMSStore(selectIsLocalVideoPluginPresent(VBHandler?.getName() || ''));
|
|
189
|
+
|
|
190
|
+
// State can be used to show active selection
|
|
191
|
+
const [background, setBackground] = useState<string | HMSVirtualBackgroundTypes>(
|
|
192
|
+
VBHandler.getBackground() as string | HMSVirtualBackgroundTypes,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
if (!track?.id) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!isPluginAdded) {
|
|
200
|
+
let vbObject = VBHandler.getVBObject();
|
|
201
|
+
if (!vbObject) {
|
|
202
|
+
VBHandler.initialisePlugin(effectsKey);
|
|
203
|
+
vbObject = VBHandler.getVBObject();
|
|
204
|
+
if (effectsKey) {
|
|
205
|
+
hmsActions.addPluginsToVideoStream([vbObject as HMSEffectsPlugin]);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}, [hmsActions, isPluginAdded, effectsKey, track?.id]);
|
|
210
|
+
|
|
211
|
+
// UI code for media picker can go here
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
This handles initialisation and adding the plugin to the video stream. The plugin takes a few seconds on first load during initialisation. Subsequent filter and effect selections should take less than a second to reflect.
|
|
217
|
+
|
|
218
|
+
The methods can be called via the `VBHandler` object:
|
|
219
|
+
```jsx
|
|
220
|
+
const setBackground = async(mediaURL : string) => {
|
|
221
|
+
await VBHandler?.setBackground(mediaURL);
|
|
222
|
+
// The selection can be highlighted using the activeBackground state
|
|
223
|
+
setActiveBackground(mediaURL);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const setBlur = async(blurAmount: number) => {
|
|
227
|
+
await VBHandler?.setBlur(blurAmount);
|
|
228
|
+
setActiveBackground(HMSVirtualBackgroundTypes.BLUR);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const removeEffects = async() => {
|
|
232
|
+
await VBHandler.removeEffects();
|
|
233
|
+
setActiveBackground(HMSVirtualBackgroundTypes.NONE);
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
The full implementation can be viewed in the [roomkit-react package](https://github.com/100mslive/web-sdks/blob/main/packages/roomkit-react/src/Prebuilt/components/VirtualBackground/VBPicker.tsx).
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
## Supported Browsers
|
|
242
|
+
|
|
243
|
+
Effects virtual background is supported on Safari, Firefox and Chromium based browsers.<br/>
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var h=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var b=(r,t)=>{for(var e in t)h(r,e,{get:t[e],enumerable:!0})},k=(r,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of p(t))!v.call(r,s)&&s!==e&&h(r,s,{get:()=>t[s],enumerable:!(i=g(t,s))||i.enumerable});return r};var S=r=>k(h({},"__esModule",{value:!0}),r);var f=(r,t,e)=>new Promise((i,s)=>{var d=a=>{try{o(e.next(a))}catch(c){s(c)}},m=a=>{try{o(e.throw(a))}catch(c){s(c)}},o=a=>a.done?i(a.value):Promise.resolve(a.value).then(d,m);o((e=e.apply(r,t)).next())});var E={};b(E,{HMSEffectsPlugin:()=>u});module.exports=S(E);var l=require("effects-sdk");var n="https://assets.100ms.live/effectsdk/3.
|
|
1
|
+
"use strict";var h=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var b=(r,t)=>{for(var e in t)h(r,e,{get:t[e],enumerable:!0})},k=(r,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of p(t))!v.call(r,s)&&s!==e&&h(r,s,{get:()=>t[s],enumerable:!(i=g(t,s))||i.enumerable});return r};var S=r=>k(h({},"__esModule",{value:!0}),r);var f=(r,t,e)=>new Promise((i,s)=>{var d=a=>{try{o(e.next(a))}catch(c){s(c)}},m=a=>{try{o(e.throw(a))}catch(c){s(c)}},o=a=>a.done?i(a.value):Promise.resolve(a.value).then(d,m);o((e=e.apply(r,t)).next())});var E={};b(E,{HMSEffectsPlugin:()=>u});module.exports=S(E);var l=require("effects-sdk");var n="https://assets.100ms.live/effectsdk/3.4.3/";var u=class{constructor(t,e){this.blurAmount=0;this.background="none";this.backgroundType="none";this.preset="balanced";this.initialised=!1;this.intervalId=null;this.effects=new l.tsvb(t),this.onInit=e,this.effects.config({sdk_url:n,models:{colorcorrector:"",facedetector:"",lowlighter:""},wasmPaths:{"ort-wasm.wasm":`${n}ort-wasm.wasm`,"ort-wasm-simd.wasm":`${n}ort-wasm-simd.wasm`}}),this.canvas=document.createElement("canvas"),this.effects.onError(i=>{(!i.type||i.type==="error")&&console.error("[HMSEffectsPlugin]",i)}),this.effects.cache(),this.effects.onReady=()=>{var i;this.effects&&(this.initialised=!0,(i=this.onInit)==null||i.call(this),this.effects.run(),this.effects.setBackgroundFitMode("fill"),this.effects.setSegmentationPreset(this.preset),this.applyEffect())}}getName(){return"HMSEffects"}executeAfterInit(t){this.initialised&&t(),this.intervalId!==null&&clearInterval(this.intervalId),this.intervalId=setInterval(()=>{this.initialised&&(clearInterval(this.intervalId),t())},100)}removeBlur(){this.blurAmount=0,this.executeAfterInit(()=>{this.effects.clearBlur()})}removeBackground(){this.background="",this.executeAfterInit(()=>{this.effects.clearBackground()})}setBlur(t){this.blurAmount=t,this.backgroundType="blur",this.removeBackground(),this.executeAfterInit(()=>{this.effects.setBlur(this.blurAmount)})}setPreset(t){return f(this,null,function*(){return this.preset=t,new Promise((e,i)=>{this.executeAfterInit(()=>{this.effects.setSegmentationPreset(this.preset).then(e).catch(i)})})})}onResolutionChange(t){this.onResolutionChangeCallback=t}getPreset(){return this.preset}removeEffects(){this.backgroundType="none",this.removeBackground(),this.removeBlur()}setBackground(t){this.background=t,this.backgroundType="image",this.removeBlur(),this.executeAfterInit(()=>{this.effects.setBackground(this.background)})}getBlurAmount(){return this.blurAmount}getBackground(){return this.background||this.backgroundType}updateCanvas(t){let{height:e,width:i}=t.getVideoTracks()[0].getSettings();this.canvas.width=i,this.canvas.height=e,this.effects.useStream(t),this.effects.toCanvas(this.canvas)}apply(t){return this.effects.clear(),this.applyEffect(),this.effects.onChangeInputResolution(()=>{var s;this.updateCanvas(t);let{height:e,width:i}=t.getVideoTracks()[0].getSettings();(s=this.onResolutionChangeCallback)==null||s.call(this,i,e)}),this.updateCanvas(t),this.canvas.captureStream(30)||t}stop(){this.removeEffects(),this.executeAfterInit(()=>{this.effects.stop()})}applyEffect(){this.blurAmount?this.setBlur(this.blurAmount):this.background&&this.setBackground(this.background)}};
|
|
2
2
|
//# sourceMappingURL=HMSEffectsPlugin.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/HMSEffectsPlugin.ts", "../../src/constants.ts"],
|
|
4
|
-
"sourcesContent": ["import { tsvb } from 'effects-sdk';\nimport { HMSMediaStreamPlugin } from '@100mslive/hms-video-store';\nimport { EFFECTS_SDK_ASSETS } from './constants';\nimport { HMSVirtualBackgroundTypes } from './interfaces';\n\nexport type HMSEffectsBackground = string | MediaStream | MediaStreamTrack | HTMLVideoElement;\n\nexport class HMSEffectsPlugin implements HMSMediaStreamPlugin {\n private effects: tsvb;\n // Ranges from 0 to 1, inclusive\n private blurAmount = 0;\n private background: HMSEffectsBackground = HMSVirtualBackgroundTypes.NONE;\n private backgroundType = HMSVirtualBackgroundTypes.NONE;\n private preset: 'balanced' | 'quality' = 'balanced';\n private initialised = false;\n private intervalId: NodeJS.Timer | null = null;\n private onInit;\n private onResolutionChangeCallback?: (width: number, height: number) => void;\n private canvas: HTMLCanvasElement;\n\n constructor(effectsSDKKey: string, onInit?: () => void) {\n this.effects = new tsvb(effectsSDKKey);\n this.onInit = onInit;\n this.effects.config({\n sdk_url: EFFECTS_SDK_ASSETS,\n models: {\n colorcorrector: '',\n facedetector: '',\n lowlighter: '',\n },\n wasmPaths: {\n 'ort-wasm.wasm': `${EFFECTS_SDK_ASSETS}ort-wasm.wasm`,\n 'ort-wasm-simd.wasm': `${EFFECTS_SDK_ASSETS}ort-wasm-simd.wasm`,\n },\n });\n this.canvas = document.createElement('canvas');\n this.effects.onError(err => {\n // currently logging info type messages as well\n if (!err.type || err.type === 'error') {\n console.error('[HMSEffectsPlugin]', err);\n }\n });\n this.effects.cache();\n this.effects.onReady = () => {\n if (this.effects) {\n this.initialised = true;\n this.onInit?.();\n this.effects.run();\n this.effects.setBackgroundFitMode('fill');\n this.effects.setSegmentationPreset(this.preset);\n this.applyEffect();\n }\n };\n }\n\n getName(): string {\n return 'HMSEffects';\n }\n\n private executeAfterInit(callback: () => void) {\n if (this.initialised) {\n callback();\n }\n\n if (this.intervalId !== null) {\n clearInterval(this.intervalId);\n }\n this.intervalId = setInterval(() => {\n if (this.initialised) {\n clearInterval(this.intervalId!);\n callback();\n }\n }, 100);\n }\n\n removeBlur() {\n this.blurAmount = 0;\n this.executeAfterInit(() => {\n this.effects.clearBlur();\n });\n }\n\n removeBackground() {\n this.background = '';\n this.executeAfterInit(() => {\n this.effects.clearBackground();\n });\n }\n\n /**\n * @param blur ranges between 0 and 1\n */\n setBlur(blur: number) {\n this.blurAmount = blur;\n this.backgroundType = HMSVirtualBackgroundTypes.BLUR;\n this.removeBackground();\n this.executeAfterInit(() => {\n this.effects.setBlur(this.blurAmount);\n });\n }\n\n /**\n * @param preset can be 'quality' or 'balanced'. The 'quality' preset has better quality but higher CPU usage than 'balanced'\n */\n async setPreset(preset: 'quality' | 'balanced') {\n this.preset = preset;\n return new Promise((resolve, reject) => {\n this.executeAfterInit(() => {\n this.effects.setSegmentationPreset(this.preset).then(resolve).catch(reject);\n });\n });\n }\n\n onResolutionChange(callback: (width: number, height: number) => void) {\n this.onResolutionChangeCallback = callback;\n }\n\n getPreset() {\n return this.preset;\n }\n\n removeEffects() {\n this.backgroundType = HMSVirtualBackgroundTypes.NONE;\n this.removeBackground();\n this.removeBlur();\n }\n\n setBackground(url: HMSEffectsBackground) {\n this.background = url;\n this.backgroundType = HMSVirtualBackgroundTypes.IMAGE;\n this.removeBlur();\n this.executeAfterInit(() => {\n this.effects.setBackground(this.background);\n });\n }\n\n getBlurAmount() {\n return this.blurAmount;\n }\n\n getBackground() {\n return this.background || this.backgroundType;\n }\n\n private updateCanvas(stream: MediaStream) {\n const { height, width } = stream.getVideoTracks()[0].getSettings();\n this.canvas.width = width!;\n this.canvas.height = height!;\n this.effects.useStream(stream);\n this.effects.toCanvas(this.canvas);\n }\n\n apply(stream: MediaStream): MediaStream {\n this.effects.clear();\n this.applyEffect();\n this.effects.onChangeInputResolution(() => {\n this.updateCanvas(stream);\n const { height, width } = stream.getVideoTracks()[0].getSettings();\n this.onResolutionChangeCallback?.(width!, height!);\n });\n this.updateCanvas(stream);\n return this.canvas.captureStream(30) || stream;\n }\n\n stop() {\n this.removeEffects();\n this.executeAfterInit(() => {\n this.effects.stop();\n });\n }\n\n private applyEffect() {\n if (this.blurAmount) {\n this.setBlur(this.blurAmount);\n } else if (this.background) {\n this.setBackground(this.background);\n }\n }\n}\n", "export const EFFECTS_SDK_ASSETS = 'https://assets.100ms.live/effectsdk/3.
|
|
4
|
+
"sourcesContent": ["import { tsvb } from 'effects-sdk';\nimport { HMSMediaStreamPlugin } from '@100mslive/hms-video-store';\nimport { EFFECTS_SDK_ASSETS } from './constants';\nimport { HMSVirtualBackgroundTypes } from './interfaces';\n\nexport type HMSEffectsBackground = string | MediaStream | MediaStreamTrack | HTMLVideoElement;\n\nexport class HMSEffectsPlugin implements HMSMediaStreamPlugin {\n private effects: tsvb;\n // Ranges from 0 to 1, inclusive\n private blurAmount = 0;\n private background: HMSEffectsBackground = HMSVirtualBackgroundTypes.NONE;\n private backgroundType = HMSVirtualBackgroundTypes.NONE;\n private preset: 'balanced' | 'quality' = 'balanced';\n private initialised = false;\n private intervalId: NodeJS.Timer | null = null;\n private onInit;\n private onResolutionChangeCallback?: (width: number, height: number) => void;\n private canvas: HTMLCanvasElement;\n\n constructor(effectsSDKKey: string, onInit?: () => void) {\n this.effects = new tsvb(effectsSDKKey);\n this.onInit = onInit;\n this.effects.config({\n sdk_url: EFFECTS_SDK_ASSETS,\n models: {\n colorcorrector: '',\n facedetector: '',\n lowlighter: '',\n },\n wasmPaths: {\n 'ort-wasm.wasm': `${EFFECTS_SDK_ASSETS}ort-wasm.wasm`,\n 'ort-wasm-simd.wasm': `${EFFECTS_SDK_ASSETS}ort-wasm-simd.wasm`,\n },\n });\n this.canvas = document.createElement('canvas');\n this.effects.onError(err => {\n // currently logging info type messages as well\n if (!err.type || err.type === 'error') {\n console.error('[HMSEffectsPlugin]', err);\n }\n });\n this.effects.cache();\n this.effects.onReady = () => {\n if (this.effects) {\n this.initialised = true;\n this.onInit?.();\n this.effects.run();\n this.effects.setBackgroundFitMode('fill');\n this.effects.setSegmentationPreset(this.preset);\n this.applyEffect();\n }\n };\n }\n\n getName(): string {\n return 'HMSEffects';\n }\n\n private executeAfterInit(callback: () => void) {\n if (this.initialised) {\n callback();\n }\n\n if (this.intervalId !== null) {\n clearInterval(this.intervalId);\n }\n this.intervalId = setInterval(() => {\n if (this.initialised) {\n clearInterval(this.intervalId!);\n callback();\n }\n }, 100);\n }\n\n removeBlur() {\n this.blurAmount = 0;\n this.executeAfterInit(() => {\n this.effects.clearBlur();\n });\n }\n\n removeBackground() {\n this.background = '';\n this.executeAfterInit(() => {\n this.effects.clearBackground();\n });\n }\n\n /**\n * @param blur ranges between 0 and 1\n */\n setBlur(blur: number) {\n this.blurAmount = blur;\n this.backgroundType = HMSVirtualBackgroundTypes.BLUR;\n this.removeBackground();\n this.executeAfterInit(() => {\n this.effects.setBlur(this.blurAmount);\n });\n }\n\n /**\n * @param preset can be 'quality' or 'balanced'. The 'quality' preset has better quality but higher CPU usage than 'balanced'\n */\n async setPreset(preset: 'quality' | 'balanced') {\n this.preset = preset;\n return new Promise((resolve, reject) => {\n this.executeAfterInit(() => {\n this.effects.setSegmentationPreset(this.preset).then(resolve).catch(reject);\n });\n });\n }\n\n onResolutionChange(callback: (width: number, height: number) => void) {\n this.onResolutionChangeCallback = callback;\n }\n\n getPreset() {\n return this.preset;\n }\n\n removeEffects() {\n this.backgroundType = HMSVirtualBackgroundTypes.NONE;\n this.removeBackground();\n this.removeBlur();\n }\n\n setBackground(url: HMSEffectsBackground) {\n this.background = url;\n this.backgroundType = HMSVirtualBackgroundTypes.IMAGE;\n this.removeBlur();\n this.executeAfterInit(() => {\n this.effects.setBackground(this.background);\n });\n }\n\n getBlurAmount() {\n return this.blurAmount;\n }\n\n getBackground() {\n return this.background || this.backgroundType;\n }\n\n private updateCanvas(stream: MediaStream) {\n const { height, width } = stream.getVideoTracks()[0].getSettings();\n this.canvas.width = width!;\n this.canvas.height = height!;\n this.effects.useStream(stream);\n this.effects.toCanvas(this.canvas);\n }\n\n apply(stream: MediaStream): MediaStream {\n this.effects.clear();\n this.applyEffect();\n this.effects.onChangeInputResolution(() => {\n this.updateCanvas(stream);\n const { height, width } = stream.getVideoTracks()[0].getSettings();\n this.onResolutionChangeCallback?.(width!, height!);\n });\n this.updateCanvas(stream);\n return this.canvas.captureStream(30) || stream;\n }\n\n stop() {\n this.removeEffects();\n this.executeAfterInit(() => {\n this.effects.stop();\n });\n }\n\n private applyEffect() {\n if (this.blurAmount) {\n this.setBlur(this.blurAmount);\n } else if (this.background) {\n this.setBackground(this.background);\n }\n }\n}\n", "export const EFFECTS_SDK_ASSETS = 'https://assets.100ms.live/effectsdk/3.4.3/';\n"],
|
|
5
5
|
"mappings": "snBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,sBAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAqB,uBCAd,IAAMC,EAAqB,6CDO3B,IAAMC,EAAN,KAAuD,CAa5D,YAAYC,EAAuBC,EAAqB,CAVxD,KAAQ,WAAa,EACrB,KAAQ,kBACR,KAAQ,sBACR,KAAQ,OAAiC,WACzC,KAAQ,YAAc,GACtB,KAAQ,WAAkC,KAMxC,KAAK,QAAU,IAAI,OAAKD,CAAa,EACrC,KAAK,OAASC,EACd,KAAK,QAAQ,OAAO,CAClB,QAASC,EACT,OAAQ,CACN,eAAgB,GAChB,aAAc,GACd,WAAY,EACd,EACA,UAAW,CACT,gBAAiB,GAAGA,CAAkB,gBACtC,qBAAsB,GAAGA,CAAkB,oBAC7C,CACF,CAAC,EACD,KAAK,OAAS,SAAS,cAAc,QAAQ,EAC7C,KAAK,QAAQ,QAAQC,GAAO,EAEtB,CAACA,EAAI,MAAQA,EAAI,OAAS,UAC5B,QAAQ,MAAM,qBAAsBA,CAAG,CAE3C,CAAC,EACD,KAAK,QAAQ,MAAM,EACnB,KAAK,QAAQ,QAAU,IAAM,CA3CjC,IAAAC,EA4CU,KAAK,UACP,KAAK,YAAc,IACnBA,EAAA,KAAK,SAAL,MAAAA,EAAA,WACA,KAAK,QAAQ,IAAI,EACjB,KAAK,QAAQ,qBAAqB,MAAM,EACxC,KAAK,QAAQ,sBAAsB,KAAK,MAAM,EAC9C,KAAK,YAAY,EAErB,CACF,CAEA,SAAkB,CAChB,MAAO,YACT,CAEQ,iBAAiBC,EAAsB,CACzC,KAAK,aACPA,EAAS,EAGP,KAAK,aAAe,MACtB,cAAc,KAAK,UAAU,EAE/B,KAAK,WAAa,YAAY,IAAM,CAC9B,KAAK,cACP,cAAc,KAAK,UAAW,EAC9BA,EAAS,EAEb,EAAG,GAAG,CACR,CAEA,YAAa,CACX,KAAK,WAAa,EAClB,KAAK,iBAAiB,IAAM,CAC1B,KAAK,QAAQ,UAAU,CACzB,CAAC,CACH,CAEA,kBAAmB,CACjB,KAAK,WAAa,GAClB,KAAK,iBAAiB,IAAM,CAC1B,KAAK,QAAQ,gBAAgB,CAC/B,CAAC,CACH,CAKA,QAAQC,EAAc,CACpB,KAAK,WAAaA,EAClB,KAAK,sBACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,IAAM,CAC1B,KAAK,QAAQ,QAAQ,KAAK,UAAU,CACtC,CAAC,CACH,CAKM,UAAUC,EAAgC,QAAAC,EAAA,sBAC9C,YAAK,OAASD,EACP,IAAI,QAAQ,CAACE,EAASC,IAAW,CACtC,KAAK,iBAAiB,IAAM,CAC1B,KAAK,QAAQ,sBAAsB,KAAK,MAAM,EAAE,KAAKD,CAAO,EAAE,MAAMC,CAAM,CAC5E,CAAC,CACH,CAAC,CACH,GAEA,mBAAmBL,EAAmD,CACpE,KAAK,2BAA6BA,CACpC,CAEA,WAAY,CACV,OAAO,KAAK,MACd,CAEA,eAAgB,CACd,KAAK,sBACL,KAAK,iBAAiB,EACtB,KAAK,WAAW,CAClB,CAEA,cAAcM,EAA2B,CACvC,KAAK,WAAaA,EAClB,KAAK,uBACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,IAAM,CAC1B,KAAK,QAAQ,cAAc,KAAK,UAAU,CAC5C,CAAC,CACH,CAEA,eAAgB,CACd,OAAO,KAAK,UACd,CAEA,eAAgB,CACd,OAAO,KAAK,YAAc,KAAK,cACjC,CAEQ,aAAaC,EAAqB,CACxC,GAAM,CAAE,OAAAC,EAAQ,MAAAC,CAAM,EAAIF,EAAO,eAAe,EAAE,CAAC,EAAE,YAAY,EACjE,KAAK,OAAO,MAAQE,EACpB,KAAK,OAAO,OAASD,EACrB,KAAK,QAAQ,UAAUD,CAAM,EAC7B,KAAK,QAAQ,SAAS,KAAK,MAAM,CACnC,CAEA,MAAMA,EAAkC,CACtC,YAAK,QAAQ,MAAM,EACnB,KAAK,YAAY,EACjB,KAAK,QAAQ,wBAAwB,IAAM,CA3J/C,IAAAR,EA4JM,KAAK,aAAaQ,CAAM,EACxB,GAAM,CAAE,OAAAC,EAAQ,MAAAC,CAAM,EAAIF,EAAO,eAAe,EAAE,CAAC,EAAE,YAAY,GACjER,EAAA,KAAK,6BAAL,MAAAA,EAAA,UAAkCU,EAAQD,EAC5C,CAAC,EACD,KAAK,aAAaD,CAAM,EACjB,KAAK,OAAO,cAAc,EAAE,GAAKA,CAC1C,CAEA,MAAO,CACL,KAAK,cAAc,EACnB,KAAK,iBAAiB,IAAM,CAC1B,KAAK,QAAQ,KAAK,CACpB,CAAC,CACH,CAEQ,aAAc,CAChB,KAAK,WACP,KAAK,QAAQ,KAAK,UAAU,EACnB,KAAK,YACd,KAAK,cAAc,KAAK,UAAU,CAEtC,CACF",
|
|
6
6
|
"names": ["HMSEffectsPlugin_exports", "__export", "HMSEffectsPlugin", "__toCommonJS", "import_effects_sdk", "EFFECTS_SDK_ASSETS", "HMSEffectsPlugin", "effectsSDKKey", "onInit", "EFFECTS_SDK_ASSETS", "err", "_a", "callback", "blur", "preset", "__async", "resolve", "reject", "url", "stream", "height", "width"]
|
|
7
7
|
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var P=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var Q=Object.prototype.hasOwnProperty;var Y=(a,t)=>()=>(t||a((t={exports:{}}).exports,t),t.exports),X=(a,t)=>{for(var e in t)P(a,e,{get:t[e],enumerable:!0})},Z=(a,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of K(t))!Q.call(a,s)&&s!==e&&P(a,s,{get:()=>t[s],enumerable:!(i=J(t,s))||i.enumerable});return a};var tt=a=>Z(P({},"__esModule",{value:!0}),a);var o=(a,t,e)=>new Promise((i,s)=>{var r=h=>{try{u(e.next(h))}catch(d){s(d)}},n=h=>{try{u(e.throw(h))}catch(d){s(d)}},u=h=>h.done?i(h.value):Promise.resolve(h.value).then(r,n);u((e=e.apply(a,t)).next())});var L=Y((mt,et)=>{et.exports={version:"1.13.25-alpha.0",license:"MIT",name:"@100mslive/hms-virtual-background",author:"100ms",module:"dist/esm/index.js",main:"dist/cjs/index.js",typings:"dist/index.d.ts",typesVersions:{"*":{hmsvbplugin:["./dist/HMSVBPlugin.d.ts"],hmseffectsplugin:["./dist/HMSEffectsPlugin.d.ts"]}},exports:{".":{import:"./dist/esm/index.js",require:"./dist/cjs/index.js",default:"./dist/esm/index.js",types:"./dist/index.d.ts"},"./hmsvbplugin":{import:"./dist/esm/HMSVBPlugin.js",require:"./dist/cjs/HMSVBPlugin.js",default:"./dist/esm/HMSVBPlugin.js",types:"./dist/HMSVBPlugin.d.ts"},"./hmseffectsplugin":{import:"./dist/esm/HMSEffectsPlugin.js",default:"./dist/esm/HMSEffectsPlugin.js",require:"./dist/cjs/HMSEffectsPlugin.js",types:"./dist/HMSEffectsPlugin.d.ts"}},repository:{type:"git",url:"https://github.com/100mslive/web-sdks.git",directory:"packages/hms-virtual-background"},files:["dist","src/tflite","src/models"],scripts:{start:'concurrently "yarn dev" "yarn types"',dev:"node ../../scripts/dev","build:only":"node ../../scripts/build",build:"yarn build:only && yarn types:build",types:"tsc -w","types:build":"tsc -p tsconfig.json",test:"jest --maxWorkers=1 --passWithNoTests",lint:"eslint -c ../../.eslintrc .","lint:fix":"yarn lint --fix",prepare:"yarn build",size:"size-limit",analyze:"size-limit --why",format:"prettier --write src/**/*.ts"},peerDependencies:{"@100mslive/hms-video-store":"0.12.25-alpha.0"},devDependencies:{"@100mslive/hms-video-store":"0.12.25-alpha.0"},dependencies:{"@mediapipe/selfie_segmentation":"^0.1.1632777926","@tensorflow-models/body-segmentation":"^1.0.1","@tensorflow/tfjs-backend-webgl":"^3.3.0","@tensorflow/tfjs-converter":"^3.19.0","@tensorflow/tfjs-core":"^3.19.0","@webassemblyjs/helper-wasm-bytecode":"1.11.1","@webassemblyjs/wasm-gen":"1.11.1","effects-sdk":"3.2.3","gifuct-js":"^2.1.2","wasm-check":"^2.0.2"},eslintIgnore:["tflite.js","tflite-simd.js","tflite.wasm","tflite-simd.wasm","defineTFLite.ts","importing.test.ts"],gitHead:"b9a15a40498feb37cf34dc6fab790cb9dcfcd775"}});var pt={};X(pt,{HMSEffectsPlugin:()=>T,HMSVBPlugin:()=>I,HMSVirtualBackgroundPlugin:()=>D,HMSVirtualBackgroundTypes:()=>p});module.exports=tt(pt);var y=require("gifuct-js"),x=require("@100mslive/hms-video-store"),Ct=require("@tensorflow/tfjs-backend-webgl");var it=L(),A=`https://unpkg.com/${it.name}/src`,C="VBProcessor",st="tflite/tflite.js",at="tflite/tflite-simd.js",nt="models/selfie_segmentation_landscape.tflite",_=a=>new Promise(function(t,e){let i=document.createElement("script");i.src=a,i.onload=t,i.onerror=e,document.head.appendChild(i)}),ot=()=>o(void 0,null,function*(){let a,t=`${A}/${at}`;yield _(t);try{a=yield createTFLiteSIMDModule()}catch(e){console.warn("SIMD not supported. You may experience poor virtual background effect."),t=`${A}/${st}`,yield _(t),a=yield createTFLiteModule()}return a}),j=()=>o(void 0,null,function*(){let a=`${A}/${nt}`,[t,e]=yield Promise.all([ot(),fetch(a)]),i=yield e.arrayBuffer(),s=t._getModelBufferMemoryOffset();return t.HEAPU8.set(new Uint8Array(i),s),t._loadModel(i.byteLength),console.debug(C,"Input memory offset:",t._getInputMemoryOffset()),console.debug(C,"Input height:",t._getInputHeight()),console.debug(C,"Input width:",t._getInputWidth()),console.debug(C,"Input channels:",t._getInputChannelCount()),t});var M="VBProcessor",rt=33,ut=L(),ht=214,dt=855,gt=120,lt=720,D=class{constructor(t,e=!1){this.backgroundType="none";this.background=t,this.enableSharpening=e,this.backgroundImage=null,this.backgroundVideo=null,this.personMaskWidth=256,this.personMaskHeight=144,this.isVirtualBackground=!1,this.blurValue="10px",this.loadModelCalled=!1,this.tfLite=null,this.modelName="landscape-segmentation",this.outputCtx=null,this.input=null,this.output=null,this.timerID=0,this.imageAspectRatio=1,this.personMaskPixelCount=this.personMaskWidth*this.personMaskHeight,this.personMask=new ImageData(this.personMaskWidth,this.personMaskHeight),this.personMaskCanvas=document.createElement("canvas"),this.personMaskCanvas.width=this.personMaskWidth,this.personMaskCanvas.height=this.personMaskHeight,this.personMaskCtx=this.personMaskCanvas.getContext("2d"),this.filters={},this.gifFrames=null,this.gifFramesIndex=0,this.gifFrameImageData=null,this.tempGifCanvas=document.createElement("canvas"),this.tempGifContext=this.tempGifCanvas.getContext("2d"),this.giflocalCount=0,this.enableSharpening=e,this.log(M,"Virtual Background plugin created"),this.setBackground(this.background)}init(){return o(this,null,function*(){this.loadModelCalled?yield this.tfLitePromise:(this.log(M,"PREVIOUS LOADED MODEL IS ",this.tfLite),this.loadModelCalled=!0,this.tfLitePromise=j(),this.tfLite=yield this.tfLitePromise),this.enableSharpening&&this.initSharpenFilter()})}isSupported(){return navigator.userAgent.indexOf("Chrome")!==-1||navigator.userAgent.indexOf("Firefox")!==-1||navigator.userAgent.indexOf("Edg")!==-1||navigator.userAgent.indexOf("Edge")!==-1}checkSupport(){let t={};return["Chrome","Firefox","Edg","Edge"].some(e=>navigator.userAgent.indexOf(e)!==-1)?t.isSupported=!0:(t.isSupported=!1,t.errType=x.HMSPluginUnsupportedTypes.PLATFORM_NOT_SUPPORTED,t.errMsg="browser not supported for plugin, see docs"),t}getName(){return ut.name}getPluginType(){return x.HMSVideoPluginType.TRANSFORM}setBackground(t){return o(this,null,function*(){if(t!=="")if(t==="none")this.log(M,"setting background to :",t),this.background="none",this.backgroundType="none",this.isVirtualBackground=!1;else if(t==="blur")this.log(M,"setting background to :",t),this.background="blur",this.backgroundType="blur",this.isVirtualBackground=!1;else if(t instanceof HTMLImageElement){this.log("setting background to image",t);let e=yield this.setImage(t);if(!e||!e.complete||!e.naturalHeight)throw new Error("Invalid image. Provide a valid and successfully loaded HTMLImageElement");this.isVirtualBackground=!0,this.backgroundImage=e,this.backgroundType="image"}else if(t instanceof HTMLVideoElement)this.log("setting background to video",t),this.backgroundVideo=t,this.backgroundVideo.crossOrigin="anonymous",this.backgroundVideo.muted=!0,this.backgroundVideo.loop=!0,this.backgroundVideo.oncanplaythrough=()=>o(this,null,function*(){this.backgroundVideo!=null&&(yield this.backgroundVideo.play(),this.isVirtualBackground=!0,this.backgroundType="video")});else if(console.log("setting gif to background"),this.gifFrames=yield this.setGiF(t),this.gifFrames!=null&&this.gifFrames.length>0)this.backgroundType="gif",this.isVirtualBackground=!0;else throw new Error("Invalid background supplied, see the docs to check supported background type");else throw new Error("Invalid background supplied, see the docs to check supported background type")})}stop(){var t,e;this.isVirtualBackground&&((t=this.backgroundImage)==null||t.removeAttribute("src"),(e=this.backgroundVideo)==null||e.removeAttribute("src"),this.backgroundType==="video"&&(this.backgroundVideo.loop=!1,this.backgroundVideo=null)),this.outputCtx&&(this.outputCtx.fillStyle="rgb(0, 0, 0)",this.outputCtx.fillRect(0,0,this.output.width,this.output.height)),this.gifFrameImageData=null,this.gifFrames=null,this.giflocalCount=0,this.gifFramesIndex=0}processVideoFrame(t,e,i){if(!t||!e)throw new Error("Plugin invalid input/output");this.input=t,this.output=e;let s=e.getContext("2d");if(s.canvas.width!==t.width&&(s.canvas.width=t.width),s.canvas.height!==t.height&&(s.canvas.height=t.height),this.backgroundType==="video"&&(this.backgroundVideo.width=t.width,this.backgroundVideo.height=t.height),this.outputCtx=s,this.imageAspectRatio=t.width/t.height,this.imageAspectRatio<=0)throw new Error("Invalid input width/height");let r=()=>o(this,null,function*(){yield this.runSegmentation(i)});this.background==="none"&&!this.isVirtualBackground?(this.outputCtx.globalCompositeOperation="copy",this.outputCtx.filter="none",this.outputCtx.drawImage(t,0,0,t.width,t.height)):r()}setImage(t){return o(this,null,function*(){return t.crossOrigin="anonymous",new Promise((e,i)=>{t.onload=()=>e(t),t.onerror=i})})}setGiF(t){return fetch(t).then(e=>e.arrayBuffer()).then(e=>(0,y.parseGIF)(e)).then(e=>(0,y.decompressFrames)(e,!0))}log(t,...e){console.info(t,...e)}resizeInputData(){this.personMaskCtx.drawImage(this.input,0,0,this.input.width,this.input.height,0,0,this.personMaskWidth,this.personMaskHeight);let t=this.personMaskCtx.getImageData(0,0,this.personMaskWidth,this.personMaskHeight),e=this.tfLite._getInputMemoryOffset()/4;for(let i=0;i<this.personMaskPixelCount;i++)this.tfLite.HEAPF32[e+i*3]=t.data[i*4]/255,this.tfLite.HEAPF32[e+i*3+1]=t.data[i*4+1]/255,this.tfLite.HEAPF32[e+i*3+2]=t.data[i*4+2]/255}infer(t){t||this.tfLite._runInference();let e=this.tfLite._getOutputMemoryOffset()/4;for(let i=0;i<this.personMaskPixelCount;i++)if(this.modelName==="meet"){let s=this.tfLite.HEAPF32[e+i*2],r=this.tfLite.HEAPF32[e+i*2+1],n=Math.max(s,r),u=Math.exp(s-n),h=Math.exp(r-n);this.personMask.data[i*4+3]=255*h/(u+h)}else if(this.modelName==="landscape-segmentation"){let s=this.tfLite.HEAPF32[e+i];this.personMask.data[i*4+3]=255*s}this.personMaskCtx.putImageData(this.personMask,0,0)}postProcessing(){this.outputCtx.globalCompositeOperation="copy",this.outputCtx.filter="none",this.isVirtualBackground?this.outputCtx.filter="blur(4px)":this.outputCtx.filter="blur(8px)",this.drawPersonMask(),this.outputCtx.globalCompositeOperation="source-in",this.outputCtx.filter="none",this.outputCtx.drawImage(this.input,0,0),this.enableSharpening&&this.output.width>ht&&this.output.height>gt&&this.output.width<dt&&this.output.height<lt&&this.sharpenFilter(),this.drawSegmentedBackground()}sharpenFilter(){let t=this.outputCtx.getImageData(0,0,this.output.width,this.output.height),e=this.filters.convolute(t);this.outputCtx.putImageData(e,0,0)}drawPersonMask(){this.outputCtx.drawImage(this.personMaskCanvas,0,0,this.personMaskWidth,this.personMaskHeight,0,0,this.output.width,this.output.height)}drawSegmentedBackground(){this.outputCtx.globalCompositeOperation="destination-over",this.outputCtx.imageSmoothingEnabled=!0,this.outputCtx.imageSmoothingQuality="high",this.isVirtualBackground?this.backgroundType==="video"&&this.backgroundVideo!=null&&this.backgroundVideo.readyState>=4?this.fitVideoToBackground():this.backgroundType==="image"?this.fitImageToBackground():this.backgroundType==="gif"&&(this.giflocalCount>this.gifFrames[this.gifFramesIndex].delay/rt?(this.gifFramesIndex++,this.gifFramesIndex>=this.gifFrames.length&&(this.gifFramesIndex=0),this.giflocalCount=0):this.giflocalCount++,this.fitGifToBackground()):this.addBlurToBackground()}runSegmentation(t){return o(this,null,function*(){this.tfLite&&(this.resizeInputData(),yield this.infer(t),this.postProcessing())})}fitVideoToBackground(){this.fitData(this.backgroundVideo,this.backgroundVideo.videoWidth,this.backgroundVideo.videoHeight)}fitImageToBackground(){this.fitData(this.backgroundImage,this.backgroundImage.width,this.backgroundImage.height)}fitGifToBackground(){if(this.gifFrameImageData==null){let t=this.gifFrames[this.gifFramesIndex].dims;this.tempGifCanvas.width=t.width,this.tempGifCanvas.height=t.height,this.gifFrameImageData=this.tempGifContext.createImageData(t.width,t.height)}this.gifFrameImageData.data.set(this.gifFrames[this.gifFramesIndex].patch),this.tempGifContext.putImageData(this.gifFrameImageData,0,0),this.fitData(this.tempGifCanvas,this.gifFrameImageData.width,this.gifFrameImageData.height)}fitData(t,e,i){let s,r,n,u;e/i<this.imageAspectRatio?(s=e,r=e/this.imageAspectRatio,n=0,u=(i-r)/2):(r=i,s=i*this.imageAspectRatio,u=0,n=(e-s)/2),this.outputCtx.drawImage(t,n,u,s,r,0,0,this.output.width,this.output.height)}addBlurToBackground(){return o(this,null,function*(){let t="15px";this.input.width<=160?t="5px":this.input.width<=320?t="10px":this.input.width<=640?t="15px":this.input.width<=960?t="20px":this.input.width<=1280?t="25px":this.input.width<=1920&&(t="30px"),this.outputCtx.filter=`blur(${t})`,this.outputCtx.drawImage(this.input,0,0,this.output.width,this.output.height)})}initSharpenFilter(){this.filters.tmpCanvas=document.createElement("canvas"),this.filters.tmpCtx=this.filters.tmpCanvas.getContext("2d"),this.filters.createImageData=(t,e)=>this.filters.tmpCtx.createImageData(t,e),this.filters.convolute=(t,e=[0,-1,0,-1,5,-1,0,-1,0],i)=>{let s=Math.round(Math.sqrt(e.length)),r=Math.floor(s/2),n=t.data,u=t.width,h=t.height,d=u,F=h,R=this.filters.createImageData(d,F),m=R.data,$=i?1:0;for(let g=0;g<F;g=g+1)for(let l=0;l<d;l=l+1){let c=(g*d+l)*4;if(n[c+3]!==0&&l<d&&g<F){let q=g,z=l,O=0,N=0,G=0,H=0;for(let f=0;f<s;f++)for(let k=0;k<s;k++){let B=q+f-r,V=z+k-r;if(B>=0&&B<h&&V>=0&&V<u){let b=(B*u+V)*4,v=e[f*s+k];O+=n[b]*v,N+=n[b+1]*v,G+=n[b+2]*v,H+=n[b+3]*v}}m[c]=O,m[c+1]=N,m[c+2]=G,m[c+3]=H+$*(255-H)}}return R}}};var U=require("@mediapipe/selfie_segmentation"),w=require("gifuct-js"),S=require("@100mslive/hms-video-store");var p=(n=>(n.BLUR="blur",n.NONE="none",n.GIF="gif",n.IMAGE="image",n.VIDEO="video",n.CANVAS="canvas",n))(p||{});var I=class{constructor(t,e){this.TAG="[HMSVBPlugin]";this.background="none";this.backgroundType="none";this.handleResults=t=>{if(!(!this.outputCanvas||!this.outputCtx)){switch(this.outputCtx.save(),this.outputCtx.clearRect(0,0,this.outputCanvas.width,this.outputCanvas.height),this.backgroundType){case"image":case"canvas":case"video":this.renderBackground(t,this.background);break;case"gif":this.renderGIF(t);break;case"blur":this.renderBlur(t);break}this.outputCtx.restore(),this.prevResults=t}};this.renderBackground=(t,e)=>{if(!this.input||!this.outputCanvas||!this.outputCtx||this.backgroundType==="none"||this.backgroundType==="blur")return;this.outputCtx.filter="none",this.outputCtx.imageSmoothingEnabled=!0,this.outputCtx.imageSmoothingQuality="high",this.outputCtx.globalCompositeOperation="source-out";let i=e instanceof HTMLVideoElement?e.videoWidth:e.width,s=e instanceof HTMLVideoElement?e.videoHeight:e.height;this.outputCtx.drawImage(e,0,0,i,s,0,0,this.outputCanvas.width,this.outputCanvas.height),this.outputCtx.globalCompositeOperation="destination-out",this.outputCtx.drawImage(t.segmentationMask,0,0,this.outputCanvas.width,this.outputCanvas.height),this.outputCtx.globalCompositeOperation="destination-atop",this.outputCtx.drawImage(this.input,0,0,this.outputCanvas.width,this.outputCanvas.height)};this.background=t,this.backgroundType=e,this.gifFrames=null,this.gifFramesIndex=0,this.gifFrameImageData=null,this.tempGifCanvas=document.createElement("canvas"),this.tempGifContext=this.tempGifCanvas.getContext("2d"),this.setBackground(this.background,this.backgroundType),this.log("Virtual background plugin initialised")}isSupported(){return this.checkSupport().isSupported}isBlurSupported(){return"filter"in CanvasRenderingContext2D.prototype}checkSupport(){let t={};return["Chrome","Firefox","Edg","Edge","Safari"].some(e=>navigator.userAgent.indexOf(e)!==-1)?t.isSupported=!0:(t.isSupported=!1,t.errType=S.HMSPluginUnsupportedTypes.PLATFORM_NOT_SUPPORTED,t.errMsg="browser not supported for plugin, see docs"),t}getName(){return"HMSVB"}getPluginType(){return S.HMSVideoPluginType.TRANSFORM}init(){return o(this,null,function*(){this.segmentation||(this.segmentation=new U.SelfieSegmentation({locateFile:t=>`https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation@0.1/${t}`}),this.segmentation.setOptions({selfieMode:!1,modelSelection:1}),this.segmentation.onResults(this.handleResults))})}setBackground(t,e){return o(this,null,function*(){if(!t)throw new Error("Invalid background supplied, see the docs to check supported background type");switch(this.prevResults=void 0,e){case"none":case"blur":this.background=t,this.backgroundType=e;break;case"image":this.log("setting background to image",t);let i=yield this.setImage(t);if(!i||!i.complete||!i.naturalHeight)throw new Error("Invalid image. Provide a valid and successfully loaded HTMLImageElement");this.background=i,this.backgroundType="image";break;case"video":this.log("setting background to video",t),this.backgroundType="none",this.background=t,this.background.crossOrigin="anonymous",this.background.muted=!0,this.background.loop=!0,this.background.playsInline=!0,this.background.oncanplaythrough=()=>o(this,null,function*(){if(this.background&&this.background instanceof HTMLVideoElement)try{yield this.background.play(),this.backgroundType="video"}catch(s){this.log("failed to play background",t)}});break;case"canvas":this.background=t,this.backgroundType="canvas";break;case"gif":if(this.log("setting gif to background",t),this.backgroundType="none",this.background=t,this.gifFrames=yield this.loadGIF(this.background),this.gifFrames!=null&&this.gifFrames.length>0)this.backgroundType="gif";else throw new Error("Invalid background supplied, see the docs to check supported background type");break;default:this.log(`backgroundType did not match with any of the supported background types - ${p}`)}})}getBackground(){return this.background}stop(){var t;this.backgroundType!=="blur"&&this.background!=="none"&&((t=this.segmentation)==null||t.reset()),this.gifFrameImageData=null,this.gifFrames=null,this.gifFramesIndex=0,this.background="none",this.backgroundType="none"}processVideoFrame(t,e,i){return o(this,null,function*(){var s;if(!t||!e)throw new Error("Plugin invalid input/output");if(this.input=t,e.width=t.width,e.height=t.height,this.outputCanvas=e,this.outputCtx=e.getContext("2d"),i&&this.prevResults){this.handleResults(this.prevResults);return}if(this.backgroundType==="none"){(s=this.outputCtx)==null||s.drawImage(t,0,0,t.width,t.height);return}yield this.segmentation.send({image:t})})}setImage(t){return o(this,null,function*(){return t.crossOrigin="anonymous",new Promise((e,i)=>{t.onload=()=>e(t),t.onerror=i})})}loadGIF(t){return fetch(t).then(e=>e.arrayBuffer()).then(e=>(0,w.parseGIF)(e)).then(e=>(0,w.decompressFrames)(e,!0))}log(...t){console.debug(this.TAG,...t)}renderBlur(t){var e,i,s;!this.outputCanvas||!this.outputCtx||this.backgroundType!=="blur"||(this.outputCtx.filter="none",this.outputCtx.globalCompositeOperation="source-out",(e=this.outputCtx)==null||e.drawImage(t.image,0,0,this.outputCanvas.width,this.outputCanvas.height),this.outputCtx.globalCompositeOperation="destination-atop",(i=this.outputCtx)==null||i.drawImage(t.segmentationMask,0,0,this.outputCanvas.width,this.outputCanvas.height),this.outputCtx.filter=`blur(${Math.floor(this.outputCanvas.width/160)*5}px)`,(s=this.outputCtx)==null||s.drawImage(t.image,0,0,this.outputCanvas.width,this.outputCanvas.height))}renderGIF(t){if(!(!this.outputCanvas||!this.outputCtx||!this.tempGifContext||this.backgroundType!=="gif")){if(this.gifFrameImageData==null){let e=this.gifFrames[this.gifFramesIndex].dims;this.tempGifCanvas.width=e.width,this.tempGifCanvas.height=e.height,this.gifFrameImageData=this.tempGifContext.createImageData(e.width,e.height)}this.gifFrameImageData.data.set(this.gifFrames[this.gifFramesIndex].patch),this.tempGifContext.putImageData(this.gifFrameImageData,0,0),this.gifFramesIndex=(this.gifFramesIndex+1)%this.gifFrames.length,this.renderBackground(t,this.tempGifCanvas)}}};var W=require("effects-sdk");var E="https://assets.100ms.live/effectsdk/3.2.3/";var T=class{constructor(t,e){this.blurAmount=0;this.background="none";this.backgroundType="none";this.preset="balanced";this.initialised=!1;this.intervalId=null;this.effects=new W.tsvb(t),this.onInit=e,this.effects.config({sdk_url:E,models:{colorcorrector:"",facedetector:"",lowlighter:""},wasmPaths:{"ort-wasm.wasm":`${E}ort-wasm.wasm`,"ort-wasm-simd.wasm":`${E}ort-wasm-simd.wasm`}}),this.canvas=document.createElement("canvas"),this.effects.onError(i=>{(!i.type||i.type==="error")&&console.error("[HMSEffectsPlugin]",i)}),this.effects.cache(),this.effects.onReady=()=>{var i;this.effects&&(this.initialised=!0,(i=this.onInit)==null||i.call(this),this.effects.run(),this.effects.setBackgroundFitMode("fill"),this.effects.setSegmentationPreset(this.preset),this.applyEffect())}}getName(){return"HMSEffects"}executeAfterInit(t){this.initialised&&t(),this.intervalId!==null&&clearInterval(this.intervalId),this.intervalId=setInterval(()=>{this.initialised&&(clearInterval(this.intervalId),t())},100)}removeBlur(){this.blurAmount=0,this.executeAfterInit(()=>{this.effects.clearBlur()})}removeBackground(){this.background="",this.executeAfterInit(()=>{this.effects.clearBackground()})}setBlur(t){this.blurAmount=t,this.backgroundType="blur",this.removeBackground(),this.executeAfterInit(()=>{this.effects.setBlur(this.blurAmount)})}setPreset(t){return o(this,null,function*(){return this.preset=t,new Promise((e,i)=>{this.executeAfterInit(()=>{this.effects.setSegmentationPreset(this.preset).then(e).catch(i)})})})}onResolutionChange(t){this.onResolutionChangeCallback=t}getPreset(){return this.preset}removeEffects(){this.backgroundType="none",this.removeBackground(),this.removeBlur()}setBackground(t){this.background=t,this.backgroundType="image",this.removeBlur(),this.executeAfterInit(()=>{this.effects.setBackground(this.background)})}getBlurAmount(){return this.blurAmount}getBackground(){return this.background||this.backgroundType}updateCanvas(t){let{height:e,width:i}=t.getVideoTracks()[0].getSettings();this.canvas.width=i,this.canvas.height=e,this.effects.useStream(t),this.effects.toCanvas(this.canvas)}apply(t){return this.effects.clear(),this.applyEffect(),this.effects.onChangeInputResolution(()=>{var s;this.updateCanvas(t);let{height:e,width:i}=t.getVideoTracks()[0].getSettings();(s=this.onResolutionChangeCallback)==null||s.call(this,i,e)}),this.updateCanvas(t),this.canvas.captureStream(30)||t}stop(){this.removeEffects(),this.executeAfterInit(()=>{this.effects.stop()})}applyEffect(){this.blurAmount?this.setBlur(this.blurAmount):this.background&&this.setBackground(this.background)}};
|
|
1
|
+
"use strict";var P=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var Q=Object.prototype.hasOwnProperty;var Y=(a,t)=>()=>(t||a((t={exports:{}}).exports,t),t.exports),X=(a,t)=>{for(var e in t)P(a,e,{get:t[e],enumerable:!0})},Z=(a,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of K(t))!Q.call(a,s)&&s!==e&&P(a,s,{get:()=>t[s],enumerable:!(i=J(t,s))||i.enumerable});return a};var tt=a=>Z(P({},"__esModule",{value:!0}),a);var o=(a,t,e)=>new Promise((i,s)=>{var r=h=>{try{u(e.next(h))}catch(d){s(d)}},n=h=>{try{u(e.throw(h))}catch(d){s(d)}},u=h=>h.done?i(h.value):Promise.resolve(h.value).then(r,n);u((e=e.apply(a,t)).next())});var L=Y((mt,et)=>{et.exports={version:"1.13.25-alpha.10",license:"MIT",name:"@100mslive/hms-virtual-background",author:"100ms",module:"dist/esm/index.js",main:"dist/cjs/index.js",typings:"dist/index.d.ts",typesVersions:{"*":{hmsvbplugin:["./dist/HMSVBPlugin.d.ts"],hmseffectsplugin:["./dist/HMSEffectsPlugin.d.ts"]}},exports:{".":{import:"./dist/esm/index.js",require:"./dist/cjs/index.js",default:"./dist/esm/index.js",types:"./dist/index.d.ts"},"./hmsvbplugin":{import:"./dist/esm/HMSVBPlugin.js",require:"./dist/cjs/HMSVBPlugin.js",default:"./dist/esm/HMSVBPlugin.js",types:"./dist/HMSVBPlugin.d.ts"},"./hmseffectsplugin":{import:"./dist/esm/HMSEffectsPlugin.js",default:"./dist/esm/HMSEffectsPlugin.js",require:"./dist/cjs/HMSEffectsPlugin.js",types:"./dist/HMSEffectsPlugin.d.ts"}},repository:{type:"git",url:"https://github.com/100mslive/web-sdks.git",directory:"packages/hms-virtual-background"},files:["dist","src/tflite","src/models"],scripts:{start:'concurrently "yarn dev" "yarn types"',dev:"node ../../scripts/dev","build:only":"node ../../scripts/build",build:"yarn build:only && yarn types:build",types:"tsc -w","types:build":"tsc -p tsconfig.json",test:"jest --maxWorkers=1 --passWithNoTests",lint:"eslint -c ../../.eslintrc .","lint:fix":"yarn lint --fix",prepare:"yarn build",size:"size-limit",analyze:"size-limit --why",format:"prettier --write src/**/*.ts"},peerDependencies:{"@100mslive/hms-video-store":"0.12.25-alpha.10"},devDependencies:{"@100mslive/hms-video-store":"0.12.25-alpha.10"},dependencies:{"@mediapipe/selfie_segmentation":"^0.1.1632777926","@tensorflow-models/body-segmentation":"^1.0.1","@tensorflow/tfjs-backend-webgl":"^3.3.0","@tensorflow/tfjs-converter":"^3.19.0","@tensorflow/tfjs-core":"^3.19.0","@webassemblyjs/helper-wasm-bytecode":"1.11.1","@webassemblyjs/wasm-gen":"1.11.1","effects-sdk":"3.4.3","gifuct-js":"^2.1.2","wasm-check":"^2.0.2"},eslintIgnore:["tflite.js","tflite-simd.js","tflite.wasm","tflite-simd.wasm","defineTFLite.ts","importing.test.ts"],gitHead:"b501de9d52ebead7150aaeaeed746c0ed1ac2c6d"}});var pt={};X(pt,{HMSEffectsPlugin:()=>T,HMSVBPlugin:()=>I,HMSVirtualBackgroundPlugin:()=>D,HMSVirtualBackgroundTypes:()=>p});module.exports=tt(pt);var y=require("gifuct-js"),x=require("@100mslive/hms-video-store"),Ct=require("@tensorflow/tfjs-backend-webgl");var it=L(),A=`https://unpkg.com/${it.name}/src`,C="VBProcessor",st="tflite/tflite.js",at="tflite/tflite-simd.js",nt="models/selfie_segmentation_landscape.tflite",_=a=>new Promise(function(t,e){let i=document.createElement("script");i.src=a,i.onload=t,i.onerror=e,document.head.appendChild(i)}),ot=()=>o(void 0,null,function*(){let a,t=`${A}/${at}`;yield _(t);try{a=yield createTFLiteSIMDModule()}catch(e){console.warn("SIMD not supported. You may experience poor virtual background effect."),t=`${A}/${st}`,yield _(t),a=yield createTFLiteModule()}return a}),j=()=>o(void 0,null,function*(){let a=`${A}/${nt}`,[t,e]=yield Promise.all([ot(),fetch(a)]),i=yield e.arrayBuffer(),s=t._getModelBufferMemoryOffset();return t.HEAPU8.set(new Uint8Array(i),s),t._loadModel(i.byteLength),console.debug(C,"Input memory offset:",t._getInputMemoryOffset()),console.debug(C,"Input height:",t._getInputHeight()),console.debug(C,"Input width:",t._getInputWidth()),console.debug(C,"Input channels:",t._getInputChannelCount()),t});var M="VBProcessor",rt=33,ut=L(),ht=214,dt=855,gt=120,lt=720,D=class{constructor(t,e=!1){this.backgroundType="none";this.background=t,this.enableSharpening=e,this.backgroundImage=null,this.backgroundVideo=null,this.personMaskWidth=256,this.personMaskHeight=144,this.isVirtualBackground=!1,this.blurValue="10px",this.loadModelCalled=!1,this.tfLite=null,this.modelName="landscape-segmentation",this.outputCtx=null,this.input=null,this.output=null,this.timerID=0,this.imageAspectRatio=1,this.personMaskPixelCount=this.personMaskWidth*this.personMaskHeight,this.personMask=new ImageData(this.personMaskWidth,this.personMaskHeight),this.personMaskCanvas=document.createElement("canvas"),this.personMaskCanvas.width=this.personMaskWidth,this.personMaskCanvas.height=this.personMaskHeight,this.personMaskCtx=this.personMaskCanvas.getContext("2d"),this.filters={},this.gifFrames=null,this.gifFramesIndex=0,this.gifFrameImageData=null,this.tempGifCanvas=document.createElement("canvas"),this.tempGifContext=this.tempGifCanvas.getContext("2d"),this.giflocalCount=0,this.enableSharpening=e,this.log(M,"Virtual Background plugin created"),this.setBackground(this.background)}init(){return o(this,null,function*(){this.loadModelCalled?yield this.tfLitePromise:(this.log(M,"PREVIOUS LOADED MODEL IS ",this.tfLite),this.loadModelCalled=!0,this.tfLitePromise=j(),this.tfLite=yield this.tfLitePromise),this.enableSharpening&&this.initSharpenFilter()})}isSupported(){return navigator.userAgent.indexOf("Chrome")!==-1||navigator.userAgent.indexOf("Firefox")!==-1||navigator.userAgent.indexOf("Edg")!==-1||navigator.userAgent.indexOf("Edge")!==-1}checkSupport(){let t={};return["Chrome","Firefox","Edg","Edge"].some(e=>navigator.userAgent.indexOf(e)!==-1)?t.isSupported=!0:(t.isSupported=!1,t.errType=x.HMSPluginUnsupportedTypes.PLATFORM_NOT_SUPPORTED,t.errMsg="browser not supported for plugin, see docs"),t}getName(){return ut.name}getPluginType(){return x.HMSVideoPluginType.TRANSFORM}setBackground(t){return o(this,null,function*(){if(t!=="")if(t==="none")this.log(M,"setting background to :",t),this.background="none",this.backgroundType="none",this.isVirtualBackground=!1;else if(t==="blur")this.log(M,"setting background to :",t),this.background="blur",this.backgroundType="blur",this.isVirtualBackground=!1;else if(t instanceof HTMLImageElement){this.log("setting background to image",t);let e=yield this.setImage(t);if(!e||!e.complete||!e.naturalHeight)throw new Error("Invalid image. Provide a valid and successfully loaded HTMLImageElement");this.isVirtualBackground=!0,this.backgroundImage=e,this.backgroundType="image"}else if(t instanceof HTMLVideoElement)this.log("setting background to video",t),this.backgroundVideo=t,this.backgroundVideo.crossOrigin="anonymous",this.backgroundVideo.muted=!0,this.backgroundVideo.loop=!0,this.backgroundVideo.oncanplaythrough=()=>o(this,null,function*(){this.backgroundVideo!=null&&(yield this.backgroundVideo.play(),this.isVirtualBackground=!0,this.backgroundType="video")});else if(console.log("setting gif to background"),this.gifFrames=yield this.setGiF(t),this.gifFrames!=null&&this.gifFrames.length>0)this.backgroundType="gif",this.isVirtualBackground=!0;else throw new Error("Invalid background supplied, see the docs to check supported background type");else throw new Error("Invalid background supplied, see the docs to check supported background type")})}stop(){var t,e;this.isVirtualBackground&&((t=this.backgroundImage)==null||t.removeAttribute("src"),(e=this.backgroundVideo)==null||e.removeAttribute("src"),this.backgroundType==="video"&&(this.backgroundVideo.loop=!1,this.backgroundVideo=null)),this.outputCtx&&(this.outputCtx.fillStyle="rgb(0, 0, 0)",this.outputCtx.fillRect(0,0,this.output.width,this.output.height)),this.gifFrameImageData=null,this.gifFrames=null,this.giflocalCount=0,this.gifFramesIndex=0}processVideoFrame(t,e,i){if(!t||!e)throw new Error("Plugin invalid input/output");this.input=t,this.output=e;let s=e.getContext("2d");if(s.canvas.width!==t.width&&(s.canvas.width=t.width),s.canvas.height!==t.height&&(s.canvas.height=t.height),this.backgroundType==="video"&&(this.backgroundVideo.width=t.width,this.backgroundVideo.height=t.height),this.outputCtx=s,this.imageAspectRatio=t.width/t.height,this.imageAspectRatio<=0)throw new Error("Invalid input width/height");let r=()=>o(this,null,function*(){yield this.runSegmentation(i)});this.background==="none"&&!this.isVirtualBackground?(this.outputCtx.globalCompositeOperation="copy",this.outputCtx.filter="none",this.outputCtx.drawImage(t,0,0,t.width,t.height)):r()}setImage(t){return o(this,null,function*(){return t.crossOrigin="anonymous",new Promise((e,i)=>{t.onload=()=>e(t),t.onerror=i})})}setGiF(t){return fetch(t).then(e=>e.arrayBuffer()).then(e=>(0,y.parseGIF)(e)).then(e=>(0,y.decompressFrames)(e,!0))}log(t,...e){console.info(t,...e)}resizeInputData(){this.personMaskCtx.drawImage(this.input,0,0,this.input.width,this.input.height,0,0,this.personMaskWidth,this.personMaskHeight);let t=this.personMaskCtx.getImageData(0,0,this.personMaskWidth,this.personMaskHeight),e=this.tfLite._getInputMemoryOffset()/4;for(let i=0;i<this.personMaskPixelCount;i++)this.tfLite.HEAPF32[e+i*3]=t.data[i*4]/255,this.tfLite.HEAPF32[e+i*3+1]=t.data[i*4+1]/255,this.tfLite.HEAPF32[e+i*3+2]=t.data[i*4+2]/255}infer(t){t||this.tfLite._runInference();let e=this.tfLite._getOutputMemoryOffset()/4;for(let i=0;i<this.personMaskPixelCount;i++)if(this.modelName==="meet"){let s=this.tfLite.HEAPF32[e+i*2],r=this.tfLite.HEAPF32[e+i*2+1],n=Math.max(s,r),u=Math.exp(s-n),h=Math.exp(r-n);this.personMask.data[i*4+3]=255*h/(u+h)}else if(this.modelName==="landscape-segmentation"){let s=this.tfLite.HEAPF32[e+i];this.personMask.data[i*4+3]=255*s}this.personMaskCtx.putImageData(this.personMask,0,0)}postProcessing(){this.outputCtx.globalCompositeOperation="copy",this.outputCtx.filter="none",this.isVirtualBackground?this.outputCtx.filter="blur(4px)":this.outputCtx.filter="blur(8px)",this.drawPersonMask(),this.outputCtx.globalCompositeOperation="source-in",this.outputCtx.filter="none",this.outputCtx.drawImage(this.input,0,0),this.enableSharpening&&this.output.width>ht&&this.output.height>gt&&this.output.width<dt&&this.output.height<lt&&this.sharpenFilter(),this.drawSegmentedBackground()}sharpenFilter(){let t=this.outputCtx.getImageData(0,0,this.output.width,this.output.height),e=this.filters.convolute(t);this.outputCtx.putImageData(e,0,0)}drawPersonMask(){this.outputCtx.drawImage(this.personMaskCanvas,0,0,this.personMaskWidth,this.personMaskHeight,0,0,this.output.width,this.output.height)}drawSegmentedBackground(){this.outputCtx.globalCompositeOperation="destination-over",this.outputCtx.imageSmoothingEnabled=!0,this.outputCtx.imageSmoothingQuality="high",this.isVirtualBackground?this.backgroundType==="video"&&this.backgroundVideo!=null&&this.backgroundVideo.readyState>=4?this.fitVideoToBackground():this.backgroundType==="image"?this.fitImageToBackground():this.backgroundType==="gif"&&(this.giflocalCount>this.gifFrames[this.gifFramesIndex].delay/rt?(this.gifFramesIndex++,this.gifFramesIndex>=this.gifFrames.length&&(this.gifFramesIndex=0),this.giflocalCount=0):this.giflocalCount++,this.fitGifToBackground()):this.addBlurToBackground()}runSegmentation(t){return o(this,null,function*(){this.tfLite&&(this.resizeInputData(),yield this.infer(t),this.postProcessing())})}fitVideoToBackground(){this.fitData(this.backgroundVideo,this.backgroundVideo.videoWidth,this.backgroundVideo.videoHeight)}fitImageToBackground(){this.fitData(this.backgroundImage,this.backgroundImage.width,this.backgroundImage.height)}fitGifToBackground(){if(this.gifFrameImageData==null){let t=this.gifFrames[this.gifFramesIndex].dims;this.tempGifCanvas.width=t.width,this.tempGifCanvas.height=t.height,this.gifFrameImageData=this.tempGifContext.createImageData(t.width,t.height)}this.gifFrameImageData.data.set(this.gifFrames[this.gifFramesIndex].patch),this.tempGifContext.putImageData(this.gifFrameImageData,0,0),this.fitData(this.tempGifCanvas,this.gifFrameImageData.width,this.gifFrameImageData.height)}fitData(t,e,i){let s,r,n,u;e/i<this.imageAspectRatio?(s=e,r=e/this.imageAspectRatio,n=0,u=(i-r)/2):(r=i,s=i*this.imageAspectRatio,u=0,n=(e-s)/2),this.outputCtx.drawImage(t,n,u,s,r,0,0,this.output.width,this.output.height)}addBlurToBackground(){return o(this,null,function*(){let t="15px";this.input.width<=160?t="5px":this.input.width<=320?t="10px":this.input.width<=640?t="15px":this.input.width<=960?t="20px":this.input.width<=1280?t="25px":this.input.width<=1920&&(t="30px"),this.outputCtx.filter=`blur(${t})`,this.outputCtx.drawImage(this.input,0,0,this.output.width,this.output.height)})}initSharpenFilter(){this.filters.tmpCanvas=document.createElement("canvas"),this.filters.tmpCtx=this.filters.tmpCanvas.getContext("2d"),this.filters.createImageData=(t,e)=>this.filters.tmpCtx.createImageData(t,e),this.filters.convolute=(t,e=[0,-1,0,-1,5,-1,0,-1,0],i)=>{let s=Math.round(Math.sqrt(e.length)),r=Math.floor(s/2),n=t.data,u=t.width,h=t.height,d=u,F=h,R=this.filters.createImageData(d,F),m=R.data,$=i?1:0;for(let g=0;g<F;g=g+1)for(let l=0;l<d;l=l+1){let c=(g*d+l)*4;if(n[c+3]!==0&&l<d&&g<F){let q=g,z=l,O=0,N=0,G=0,H=0;for(let f=0;f<s;f++)for(let k=0;k<s;k++){let B=q+f-r,V=z+k-r;if(B>=0&&B<h&&V>=0&&V<u){let b=(B*u+V)*4,v=e[f*s+k];O+=n[b]*v,N+=n[b+1]*v,G+=n[b+2]*v,H+=n[b+3]*v}}m[c]=O,m[c+1]=N,m[c+2]=G,m[c+3]=H+$*(255-H)}}return R}}};var U=require("@mediapipe/selfie_segmentation"),w=require("gifuct-js"),S=require("@100mslive/hms-video-store");var p=(n=>(n.BLUR="blur",n.NONE="none",n.GIF="gif",n.IMAGE="image",n.VIDEO="video",n.CANVAS="canvas",n))(p||{});var I=class{constructor(t,e){this.TAG="[HMSVBPlugin]";this.background="none";this.backgroundType="none";this.handleResults=t=>{if(!(!this.outputCanvas||!this.outputCtx)){switch(this.outputCtx.save(),this.outputCtx.clearRect(0,0,this.outputCanvas.width,this.outputCanvas.height),this.backgroundType){case"image":case"canvas":case"video":this.renderBackground(t,this.background);break;case"gif":this.renderGIF(t);break;case"blur":this.renderBlur(t);break}this.outputCtx.restore(),this.prevResults=t}};this.renderBackground=(t,e)=>{if(!this.input||!this.outputCanvas||!this.outputCtx||this.backgroundType==="none"||this.backgroundType==="blur")return;this.outputCtx.filter="none",this.outputCtx.imageSmoothingEnabled=!0,this.outputCtx.imageSmoothingQuality="high",this.outputCtx.globalCompositeOperation="source-out";let i=e instanceof HTMLVideoElement?e.videoWidth:e.width,s=e instanceof HTMLVideoElement?e.videoHeight:e.height;this.outputCtx.drawImage(e,0,0,i,s,0,0,this.outputCanvas.width,this.outputCanvas.height),this.outputCtx.globalCompositeOperation="destination-out",this.outputCtx.drawImage(t.segmentationMask,0,0,this.outputCanvas.width,this.outputCanvas.height),this.outputCtx.globalCompositeOperation="destination-atop",this.outputCtx.drawImage(this.input,0,0,this.outputCanvas.width,this.outputCanvas.height)};this.background=t,this.backgroundType=e,this.gifFrames=null,this.gifFramesIndex=0,this.gifFrameImageData=null,this.tempGifCanvas=document.createElement("canvas"),this.tempGifContext=this.tempGifCanvas.getContext("2d"),this.setBackground(this.background,this.backgroundType),this.log("Virtual background plugin initialised")}isSupported(){return this.checkSupport().isSupported}isBlurSupported(){return"filter"in CanvasRenderingContext2D.prototype}checkSupport(){let t={};return["Chrome","Firefox","Edg","Edge","Safari"].some(e=>navigator.userAgent.indexOf(e)!==-1)?t.isSupported=!0:(t.isSupported=!1,t.errType=S.HMSPluginUnsupportedTypes.PLATFORM_NOT_SUPPORTED,t.errMsg="browser not supported for plugin, see docs"),t}getName(){return"HMSVB"}getPluginType(){return S.HMSVideoPluginType.TRANSFORM}init(){return o(this,null,function*(){this.segmentation||(this.segmentation=new U.SelfieSegmentation({locateFile:t=>`https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation@0.1/${t}`}),this.segmentation.setOptions({selfieMode:!1,modelSelection:1}),this.segmentation.onResults(this.handleResults))})}setBackground(t,e){return o(this,null,function*(){if(!t)throw new Error("Invalid background supplied, see the docs to check supported background type");switch(this.prevResults=void 0,e){case"none":case"blur":this.background=t,this.backgroundType=e;break;case"image":this.log("setting background to image",t);let i=yield this.setImage(t);if(!i||!i.complete||!i.naturalHeight)throw new Error("Invalid image. Provide a valid and successfully loaded HTMLImageElement");this.background=i,this.backgroundType="image";break;case"video":this.log("setting background to video",t),this.backgroundType="none",this.background=t,this.background.crossOrigin="anonymous",this.background.muted=!0,this.background.loop=!0,this.background.playsInline=!0,this.background.oncanplaythrough=()=>o(this,null,function*(){if(this.background&&this.background instanceof HTMLVideoElement)try{yield this.background.play(),this.backgroundType="video"}catch(s){this.log("failed to play background",t)}});break;case"canvas":this.background=t,this.backgroundType="canvas";break;case"gif":if(this.log("setting gif to background",t),this.backgroundType="none",this.background=t,this.gifFrames=yield this.loadGIF(this.background),this.gifFrames!=null&&this.gifFrames.length>0)this.backgroundType="gif";else throw new Error("Invalid background supplied, see the docs to check supported background type");break;default:this.log(`backgroundType did not match with any of the supported background types - ${p}`)}})}getBackground(){return this.background}stop(){var t;this.backgroundType!=="blur"&&this.background!=="none"&&((t=this.segmentation)==null||t.reset()),this.gifFrameImageData=null,this.gifFrames=null,this.gifFramesIndex=0,this.background="none",this.backgroundType="none"}processVideoFrame(t,e,i){return o(this,null,function*(){var s;if(!t||!e)throw new Error("Plugin invalid input/output");if(this.input=t,e.width=t.width,e.height=t.height,this.outputCanvas=e,this.outputCtx=e.getContext("2d"),i&&this.prevResults){this.handleResults(this.prevResults);return}if(this.backgroundType==="none"){(s=this.outputCtx)==null||s.drawImage(t,0,0,t.width,t.height);return}yield this.segmentation.send({image:t})})}setImage(t){return o(this,null,function*(){return t.crossOrigin="anonymous",new Promise((e,i)=>{t.onload=()=>e(t),t.onerror=i})})}loadGIF(t){return fetch(t).then(e=>e.arrayBuffer()).then(e=>(0,w.parseGIF)(e)).then(e=>(0,w.decompressFrames)(e,!0))}log(...t){console.debug(this.TAG,...t)}renderBlur(t){var e,i,s;!this.outputCanvas||!this.outputCtx||this.backgroundType!=="blur"||(this.outputCtx.filter="none",this.outputCtx.globalCompositeOperation="source-out",(e=this.outputCtx)==null||e.drawImage(t.image,0,0,this.outputCanvas.width,this.outputCanvas.height),this.outputCtx.globalCompositeOperation="destination-atop",(i=this.outputCtx)==null||i.drawImage(t.segmentationMask,0,0,this.outputCanvas.width,this.outputCanvas.height),this.outputCtx.filter=`blur(${Math.floor(this.outputCanvas.width/160)*5}px)`,(s=this.outputCtx)==null||s.drawImage(t.image,0,0,this.outputCanvas.width,this.outputCanvas.height))}renderGIF(t){if(!(!this.outputCanvas||!this.outputCtx||!this.tempGifContext||this.backgroundType!=="gif")){if(this.gifFrameImageData==null){let e=this.gifFrames[this.gifFramesIndex].dims;this.tempGifCanvas.width=e.width,this.tempGifCanvas.height=e.height,this.gifFrameImageData=this.tempGifContext.createImageData(e.width,e.height)}this.gifFrameImageData.data.set(this.gifFrames[this.gifFramesIndex].patch),this.tempGifContext.putImageData(this.gifFrameImageData,0,0),this.gifFramesIndex=(this.gifFramesIndex+1)%this.gifFrames.length,this.renderBackground(t,this.tempGifCanvas)}}};var W=require("effects-sdk");var E="https://assets.100ms.live/effectsdk/3.4.3/";var T=class{constructor(t,e){this.blurAmount=0;this.background="none";this.backgroundType="none";this.preset="balanced";this.initialised=!1;this.intervalId=null;this.effects=new W.tsvb(t),this.onInit=e,this.effects.config({sdk_url:E,models:{colorcorrector:"",facedetector:"",lowlighter:""},wasmPaths:{"ort-wasm.wasm":`${E}ort-wasm.wasm`,"ort-wasm-simd.wasm":`${E}ort-wasm-simd.wasm`}}),this.canvas=document.createElement("canvas"),this.effects.onError(i=>{(!i.type||i.type==="error")&&console.error("[HMSEffectsPlugin]",i)}),this.effects.cache(),this.effects.onReady=()=>{var i;this.effects&&(this.initialised=!0,(i=this.onInit)==null||i.call(this),this.effects.run(),this.effects.setBackgroundFitMode("fill"),this.effects.setSegmentationPreset(this.preset),this.applyEffect())}}getName(){return"HMSEffects"}executeAfterInit(t){this.initialised&&t(),this.intervalId!==null&&clearInterval(this.intervalId),this.intervalId=setInterval(()=>{this.initialised&&(clearInterval(this.intervalId),t())},100)}removeBlur(){this.blurAmount=0,this.executeAfterInit(()=>{this.effects.clearBlur()})}removeBackground(){this.background="",this.executeAfterInit(()=>{this.effects.clearBackground()})}setBlur(t){this.blurAmount=t,this.backgroundType="blur",this.removeBackground(),this.executeAfterInit(()=>{this.effects.setBlur(this.blurAmount)})}setPreset(t){return o(this,null,function*(){return this.preset=t,new Promise((e,i)=>{this.executeAfterInit(()=>{this.effects.setSegmentationPreset(this.preset).then(e).catch(i)})})})}onResolutionChange(t){this.onResolutionChangeCallback=t}getPreset(){return this.preset}removeEffects(){this.backgroundType="none",this.removeBackground(),this.removeBlur()}setBackground(t){this.background=t,this.backgroundType="image",this.removeBlur(),this.executeAfterInit(()=>{this.effects.setBackground(this.background)})}getBlurAmount(){return this.blurAmount}getBackground(){return this.background||this.backgroundType}updateCanvas(t){let{height:e,width:i}=t.getVideoTracks()[0].getSettings();this.canvas.width=i,this.canvas.height=e,this.effects.useStream(t),this.effects.toCanvas(this.canvas)}apply(t){return this.effects.clear(),this.applyEffect(),this.effects.onChangeInputResolution(()=>{var s;this.updateCanvas(t);let{height:e,width:i}=t.getVideoTracks()[0].getSettings();(s=this.onResolutionChangeCallback)==null||s.call(this,i,e)}),this.updateCanvas(t),this.canvas.captureStream(30)||t}stop(){this.removeEffects(),this.executeAfterInit(()=>{this.effects.stop()})}applyEffect(){this.blurAmount?this.setBlur(this.blurAmount):this.background&&this.setBackground(this.background)}};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|