@pexip/media 21.0.0 → 22.0.0
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 +46 -0
- package/README.md +20 -32
- package/api-docs/README.mdx +21 -35
- package/api-docs/functions/proxyWithLog.mdx +33 -0
- package/api-docs/interfaces/ExtendedMediaTrackSettings.mdx +9 -5
- package/api-docs/interfaces/PreviewControllerProps.mdx +1 -0
- package/api-docs/interfaces/PreviewStreamParams.mdx +1 -0
- package/dist/audioMixingProcessor.d.ts +4 -2
- package/dist/audioMixingProcessor.js +22 -12
- package/dist/audioProcessor.d.ts +7 -2
- package/dist/audioProcessor.js +25 -20
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/logger.js +8 -0
- package/dist/media.js +5 -5
- package/dist/previewController.d.ts +3 -1
- package/dist/previewController.js +23 -8
- package/dist/typeGuard.d.ts +1 -2
- package/dist/typeGuard.js +0 -3
- package/dist/types.d.ts +7 -14
- package/dist/utils.js +4 -3
- package/dist/videoProcessor.d.ts +40 -22
- package/dist/videoProcessor.js +225 -245
- package/package.json +10 -10
- package/api-docs/functions/isVideoStreamTrackProcessorAPIs.mdx +0 -13
- package/api-docs/type-aliases/Segmenters.mdx +0 -3
- package/api-docs/type-aliases/VideoStreamTrackProcessorAPIs.mdx +0 -7
package/dist/videoProcessor.js
CHANGED
|
@@ -1,90 +1,93 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { isRenderEffects } from '@pexip/media-processor';
|
|
2
|
+
import { extractConstraints, getValueFromConstrainNumber, } from '@pexip/media-control';
|
|
3
|
+
import { hasOwn, isEmpty } from '@pexip/utils';
|
|
4
4
|
import { createMediaTrack, getBlurKernelSize, getTentBlurSize } from './utils';
|
|
5
5
|
import { logger, proxyWithLog } from './logger';
|
|
6
6
|
import { isVideoContentHint } from './typeGuard';
|
|
7
7
|
import { PROCESSOR_LABELS } from './constants';
|
|
8
|
-
const FEATURE_KEYS =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
|
|
38
|
-
];
|
|
39
|
-
const getVideoConstraints = extractConstraintsWithKeys(FEATURE_KEYS);
|
|
8
|
+
const FEATURE_KEYS = {
|
|
9
|
+
backgroundBlurAmount: 'number',
|
|
10
|
+
backgroundImageUrl: 'string',
|
|
11
|
+
backgroundThreshold: 'number',
|
|
12
|
+
maskCombineRatio: 'number',
|
|
13
|
+
edgeBlurAmount: 'number',
|
|
14
|
+
foregroundThreshold: 'number',
|
|
15
|
+
frameRate: 'number',
|
|
16
|
+
videoSegmentation: 'string',
|
|
17
|
+
width: 'number',
|
|
18
|
+
height: 'number',
|
|
19
|
+
pan: 'boolean',
|
|
20
|
+
tilt: 'boolean',
|
|
21
|
+
zoom: 'boolean',
|
|
22
|
+
contentHint: 'string',
|
|
23
|
+
sigmaSpace: 'number',
|
|
24
|
+
sigmaRangeLo: 'number',
|
|
25
|
+
sigmaRangeHi: 'number',
|
|
26
|
+
excludeBystanders: 'boolean',
|
|
27
|
+
personCenterX: 'number',
|
|
28
|
+
personCenterY: 'number',
|
|
29
|
+
morphErodeRadiusPx: 'number',
|
|
30
|
+
morphPass: 'number',
|
|
31
|
+
morphDilateRadiusPx: 'number',
|
|
32
|
+
lightWrapIntensity: 'number',
|
|
33
|
+
lightWrapTightness: 'number',
|
|
34
|
+
lightWrapEdgeBand: 'number',
|
|
35
|
+
lightWrapBlurAmount: 'number',
|
|
36
|
+
downSampleFactor: 'number',
|
|
37
|
+
};
|
|
40
38
|
export const updateFeatureProps = (constraints, props) => {
|
|
41
|
-
const
|
|
42
|
-
|
|
39
|
+
const features = {};
|
|
40
|
+
if (constraints === undefined || typeof constraints === 'boolean') {
|
|
41
|
+
return features;
|
|
42
|
+
}
|
|
43
|
+
for (const k of Object.keys(constraints)) {
|
|
44
|
+
const key = k;
|
|
45
|
+
if (!FEATURE_KEYS[key]) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
43
48
|
switch (key) {
|
|
44
49
|
case 'contentHint': {
|
|
45
|
-
const [[feature = ''] = []] =
|
|
50
|
+
const [[feature = ''] = []] = extractConstraints(key)(constraints);
|
|
46
51
|
if (isVideoContentHint(feature) && props[key] !== feature) {
|
|
47
52
|
props[key] = feature;
|
|
48
|
-
|
|
49
|
-
return accm;
|
|
53
|
+
features[key] = feature;
|
|
50
54
|
}
|
|
51
|
-
|
|
55
|
+
break;
|
|
52
56
|
}
|
|
53
57
|
case 'videoSegmentation': {
|
|
54
|
-
const [[feature] = []] =
|
|
58
|
+
const [[feature] = []] = extractConstraints(key)(constraints);
|
|
55
59
|
if (isRenderEffects(feature) && props[key] !== feature) {
|
|
56
60
|
props[key] = feature;
|
|
57
|
-
|
|
58
|
-
return accm;
|
|
59
|
-
}
|
|
60
|
-
return accm;
|
|
61
|
-
}
|
|
62
|
-
case 'videoSegmentationModel': {
|
|
63
|
-
const [[feature] = []] = extracted[key];
|
|
64
|
-
if (isSegmentationModel(feature) && props[key] !== feature) {
|
|
65
|
-
props[key] = feature;
|
|
66
|
-
accm[key] = feature;
|
|
67
|
-
return accm;
|
|
61
|
+
features[key] = feature;
|
|
68
62
|
}
|
|
69
|
-
|
|
63
|
+
break;
|
|
70
64
|
}
|
|
71
65
|
case 'backgroundImageUrl': {
|
|
72
|
-
const [[feature] = []] =
|
|
66
|
+
const [[feature] = []] = extractConstraints(key)(constraints);
|
|
73
67
|
if (feature) {
|
|
74
68
|
props[key] = feature;
|
|
75
|
-
|
|
76
|
-
return accm;
|
|
69
|
+
features[key] = feature;
|
|
77
70
|
}
|
|
78
|
-
|
|
71
|
+
break;
|
|
79
72
|
}
|
|
80
73
|
case 'backgroundBlurAmount':
|
|
74
|
+
case 'edgeBlurAmount':
|
|
75
|
+
case 'lightWrapBlurAmount': {
|
|
76
|
+
const [feature] = extractConstraints(key)(constraints);
|
|
77
|
+
if (feature !== undefined) {
|
|
78
|
+
const value = getValueFromConstrainNumber(feature);
|
|
79
|
+
if (props[key] !== value) {
|
|
80
|
+
props[key] = value;
|
|
81
|
+
features[key] = value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
81
86
|
case 'backgroundThreshold':
|
|
82
87
|
case 'downSampleFactor':
|
|
83
|
-
case 'edgeBlurAmount':
|
|
84
88
|
case 'foregroundThreshold':
|
|
85
89
|
case 'frameRate':
|
|
86
90
|
case 'height':
|
|
87
|
-
case 'lightWrapBlurAmount':
|
|
88
91
|
case 'lightWrapEdgeBand':
|
|
89
92
|
case 'lightWrapIntensity':
|
|
90
93
|
case 'lightWrapTightness':
|
|
@@ -98,34 +101,105 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
98
101
|
case 'sigmaRangeLo':
|
|
99
102
|
case 'sigmaSpace':
|
|
100
103
|
case 'width': {
|
|
101
|
-
const [feature] =
|
|
104
|
+
const [feature] = extractConstraints(key)(constraints);
|
|
102
105
|
if (feature !== undefined) {
|
|
103
106
|
const value = getValueFromConstrainNumber(feature);
|
|
104
107
|
if (props[key] !== value) {
|
|
105
108
|
props[key] = value;
|
|
106
|
-
|
|
107
|
-
return accm;
|
|
109
|
+
features[key] = value;
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
|
-
|
|
112
|
+
break;
|
|
111
113
|
}
|
|
112
114
|
case 'pan':
|
|
113
115
|
case 'tilt':
|
|
114
116
|
case 'zoom': {
|
|
115
|
-
const [feature] =
|
|
117
|
+
const [feature] = extractConstraints(key)(constraints);
|
|
116
118
|
if (feature !== undefined && props[key] !== feature) {
|
|
117
119
|
props[key] = feature;
|
|
118
|
-
|
|
119
|
-
return accm;
|
|
120
|
+
features[key] = feature;
|
|
120
121
|
}
|
|
121
|
-
|
|
122
|
+
break;
|
|
122
123
|
}
|
|
123
124
|
default:
|
|
124
|
-
|
|
125
|
+
break;
|
|
125
126
|
}
|
|
126
|
-
}
|
|
127
|
+
}
|
|
128
|
+
return features;
|
|
129
|
+
};
|
|
130
|
+
export const mapFeatureToSettings = (props) => {
|
|
131
|
+
return new Proxy({}, {
|
|
132
|
+
get(_target, p, receiver) {
|
|
133
|
+
switch (p) {
|
|
134
|
+
case 'tilt':
|
|
135
|
+
case 'zoom':
|
|
136
|
+
case 'pan': {
|
|
137
|
+
if (props[p] === undefined || props[p] === false) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
default: {
|
|
143
|
+
return Reflect.get(props, p, receiver);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
has(_target, p) {
|
|
148
|
+
return p in props;
|
|
149
|
+
},
|
|
150
|
+
ownKeys() {
|
|
151
|
+
return Reflect.ownKeys(props);
|
|
152
|
+
},
|
|
153
|
+
getOwnPropertyDescriptor(_target, p) {
|
|
154
|
+
if (hasOwn(props, p)) {
|
|
155
|
+
return {
|
|
156
|
+
configurable: true,
|
|
157
|
+
enumerable: true,
|
|
158
|
+
writable: true,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return undefined;
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
export const mapSettingsToFeatures = (settings) => {
|
|
166
|
+
return new Proxy({}, {
|
|
167
|
+
get(_target, p, receiver) {
|
|
168
|
+
switch (p) {
|
|
169
|
+
case 'tilt':
|
|
170
|
+
case 'zoom':
|
|
171
|
+
case 'pan': {
|
|
172
|
+
if (settings[p] === undefined) {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
default: {
|
|
178
|
+
return Reflect.get(settings, p, receiver);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
has(_target, p) {
|
|
183
|
+
return p in settings;
|
|
184
|
+
},
|
|
185
|
+
ownKeys() {
|
|
186
|
+
return Reflect.ownKeys(settings);
|
|
187
|
+
},
|
|
188
|
+
getOwnPropertyDescriptor(target, p) {
|
|
189
|
+
if (hasOwn(settings, p)) {
|
|
190
|
+
return {
|
|
191
|
+
configurable: true,
|
|
192
|
+
enumerable: true,
|
|
193
|
+
writable: true,
|
|
194
|
+
value: this.get?.(target, p, undefined),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return undefined;
|
|
198
|
+
},
|
|
199
|
+
});
|
|
127
200
|
};
|
|
128
|
-
const applyFeatures = (
|
|
201
|
+
const applyFeatures = async (processor, features, referenceProcessingHeight) => {
|
|
202
|
+
const renderOptions = {};
|
|
129
203
|
for (const key in features) {
|
|
130
204
|
const k = key;
|
|
131
205
|
switch (k) {
|
|
@@ -144,23 +218,24 @@ const applyFeatures = (transformer, features, referenceProcessingHeight) => {
|
|
|
144
218
|
case 'backgroundThreshold': {
|
|
145
219
|
const value = features[k];
|
|
146
220
|
if (value !== undefined) {
|
|
147
|
-
|
|
221
|
+
renderOptions[k] = value;
|
|
148
222
|
}
|
|
149
223
|
break;
|
|
150
224
|
}
|
|
151
225
|
case 'excludeBystanders': {
|
|
152
226
|
const value = features[k];
|
|
153
227
|
if (value !== undefined) {
|
|
154
|
-
|
|
228
|
+
renderOptions[k] = value;
|
|
155
229
|
}
|
|
156
230
|
break;
|
|
157
231
|
}
|
|
158
232
|
case 'personCenterX': {
|
|
159
233
|
const value = features[k];
|
|
160
234
|
if (value !== undefined) {
|
|
161
|
-
|
|
235
|
+
renderOptions.personCenter = [
|
|
162
236
|
value,
|
|
163
|
-
|
|
237
|
+
renderOptions.personCenter?.[1] ??
|
|
238
|
+
processor.renderOptions.personCenter[1],
|
|
164
239
|
];
|
|
165
240
|
}
|
|
166
241
|
break;
|
|
@@ -168,8 +243,9 @@ const applyFeatures = (transformer, features, referenceProcessingHeight) => {
|
|
|
168
243
|
case 'personCenterY': {
|
|
169
244
|
const value = features[k];
|
|
170
245
|
if (value !== undefined) {
|
|
171
|
-
|
|
172
|
-
|
|
246
|
+
renderOptions.personCenter = [
|
|
247
|
+
renderOptions.personCenter?.[0] ??
|
|
248
|
+
processor.renderOptions.personCenter[0],
|
|
173
249
|
value,
|
|
174
250
|
];
|
|
175
251
|
}
|
|
@@ -179,28 +255,29 @@ const applyFeatures = (transformer, features, referenceProcessingHeight) => {
|
|
|
179
255
|
case 'backgroundBlurAmount': {
|
|
180
256
|
const value = features[k];
|
|
181
257
|
if (value !== undefined) {
|
|
182
|
-
|
|
258
|
+
renderOptions[k] = getBlurKernelSize(value, referenceProcessingHeight ?? processor.processingHeight, processor.processingHeight);
|
|
183
259
|
}
|
|
184
260
|
break;
|
|
185
261
|
}
|
|
186
262
|
case 'edgeBlurAmount': {
|
|
187
263
|
const value = features[k];
|
|
188
264
|
if (value !== undefined) {
|
|
189
|
-
|
|
265
|
+
renderOptions[k] = getTentBlurSize(value, referenceProcessingHeight ?? processor.processingHeight, processor.processingHeight);
|
|
190
266
|
}
|
|
191
267
|
break;
|
|
192
268
|
}
|
|
193
269
|
case 'videoSegmentation': {
|
|
194
270
|
const value = features[k];
|
|
195
|
-
if (value && value !==
|
|
196
|
-
|
|
271
|
+
if (value && value !== processor.renderOptions.effects) {
|
|
272
|
+
renderOptions.effects = value;
|
|
197
273
|
}
|
|
198
274
|
break;
|
|
199
275
|
}
|
|
200
276
|
case 'backgroundImageUrl': {
|
|
201
277
|
const value = features[k];
|
|
202
|
-
if (value &&
|
|
203
|
-
|
|
278
|
+
if (value &&
|
|
279
|
+
value !== processor.renderOptions.backgroundImageUrl) {
|
|
280
|
+
renderOptions.backgroundImageUrl = value;
|
|
204
281
|
}
|
|
205
282
|
break;
|
|
206
283
|
}
|
|
@@ -209,74 +286,19 @@ const applyFeatures = (transformer, features, referenceProcessingHeight) => {
|
|
|
209
286
|
}
|
|
210
287
|
}
|
|
211
288
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (shouldUseStreamTrackProcessor &&
|
|
215
|
-
'MediaStreamTrackProcessor' in window) {
|
|
216
|
-
return createVideoTrackProcessor();
|
|
289
|
+
if (!isEmpty(renderOptions)) {
|
|
290
|
+
await processor.update({ renderOptions });
|
|
217
291
|
}
|
|
218
|
-
return createVideoTrackProcessorWithFallback(...params);
|
|
219
292
|
};
|
|
220
293
|
export const createVideoStreamProcess = ({ backgroundImageUrl, dynamicProcessingDimensions = () => false, backgroundThreshold, downSampleFactor, foregroundThreshold, lightWrapEdgeBand, lightWrapIntensity, lightWrapTightness, morphDilateRadiusPx, morphErodeRadiusPx, morphPass, personCenterX, personCenterY, sigmaSpace, sigmaRangeHi, sigmaRangeLo, frameRate, gpuAPI = () => 'webgl', // dynamically changing the config will not be picked up, not a priority for now
|
|
221
|
-
label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineRatio, processingHeight, processingWidth, shouldEnable, stopAsMute = () => false,
|
|
222
|
-
const videoSegmentationModel = options.videoSegmentationModel ?? 'selfie';
|
|
223
|
-
const segmenter = options.segmenters[videoSegmentationModel];
|
|
224
|
-
if (!segmenter) {
|
|
225
|
-
throw new Error('Segmenter is undefined');
|
|
226
|
-
}
|
|
294
|
+
label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineRatio, processingHeight, processingWidth, shouldEnable, stopAsMute = () => false, videoSegmentation, signals, getVideoProcessor, ...options }) => {
|
|
227
295
|
const backgroundBlurAmount = options.backgroundBlurAmount &&
|
|
228
296
|
getBlurKernelSize(options.backgroundBlurAmount, referenceProcessingHeight ?? processingHeight, processingHeight);
|
|
229
297
|
const lightWrapBlurAmount = options.lightWrapBlurAmount &&
|
|
230
298
|
getBlurKernelSize(options.lightWrapBlurAmount, referenceProcessingHeight ?? processingHeight, processingHeight);
|
|
231
299
|
const edgeBlurAmount = options.edgeBlurAmount &&
|
|
232
300
|
getTentBlurSize(options.edgeBlurAmount, referenceProcessingHeight ?? processingHeight, processingHeight);
|
|
233
|
-
const transformer = options.transformer ??
|
|
234
|
-
createCanvasTransform(segmenter, {
|
|
235
|
-
backgroundBlurAmount,
|
|
236
|
-
backgroundImageUrl,
|
|
237
|
-
backgroundThreshold,
|
|
238
|
-
downSampleFactor,
|
|
239
|
-
edgeBlurAmount,
|
|
240
|
-
effects: videoSegmentation,
|
|
241
|
-
foregroundThreshold,
|
|
242
|
-
height: processingHeight,
|
|
243
|
-
lightWrapBlurAmount,
|
|
244
|
-
lightWrapEdgeBand,
|
|
245
|
-
lightWrapIntensity,
|
|
246
|
-
lightWrapTightness,
|
|
247
|
-
maskCombineRatio,
|
|
248
|
-
morphDilateRadiusPx,
|
|
249
|
-
morphErodeRadiusPx,
|
|
250
|
-
morphPass,
|
|
251
|
-
personCenter: personCenterX !== undefined && personCenterY !== undefined
|
|
252
|
-
? [personCenterX, personCenterY]
|
|
253
|
-
: undefined,
|
|
254
|
-
sigmaRangeHi,
|
|
255
|
-
sigmaRangeLo,
|
|
256
|
-
sigmaSpace,
|
|
257
|
-
width: processingWidth,
|
|
258
|
-
});
|
|
259
|
-
const proxy = proxyWithLog(logger, label);
|
|
260
|
-
let _videoProcessor;
|
|
261
301
|
const props = {
|
|
262
|
-
videoSegmentationModel,
|
|
263
|
-
segmenters: {
|
|
264
|
-
selfie: options.segmenters.selfie &&
|
|
265
|
-
proxy(options.segmenters.selfie, 'Segmenter'),
|
|
266
|
-
deeplabV3: options.segmenters.deeplabV3 &&
|
|
267
|
-
proxy(options.segmenters.deeplabV3, 'Segmenter'),
|
|
268
|
-
},
|
|
269
|
-
transformer: proxy(transformer, 'Transformer'),
|
|
270
|
-
videoProcessor: () => {
|
|
271
|
-
if (!_videoProcessor) {
|
|
272
|
-
_videoProcessor = proxy(createVideoProcessor([transformer], getTrackProcessor(trackProcessorAPI() === 'stream', {
|
|
273
|
-
width: processingWidth,
|
|
274
|
-
height: processingHeight,
|
|
275
|
-
frameRate,
|
|
276
|
-
})), 'VideoProcessor');
|
|
277
|
-
}
|
|
278
|
-
return _videoProcessor;
|
|
279
|
-
},
|
|
280
302
|
videoSegmentation,
|
|
281
303
|
backgroundBlurAmount,
|
|
282
304
|
backgroundImageUrl,
|
|
@@ -298,7 +320,6 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
|
|
|
298
320
|
sigmaRangeHi,
|
|
299
321
|
sigmaRangeLo,
|
|
300
322
|
sigmaSpace,
|
|
301
|
-
hasInitialized: options.hasInitializedDeps ?? false,
|
|
302
323
|
};
|
|
303
324
|
return async (prevMediaTrack) => {
|
|
304
325
|
const features = updateFeatureProps(prevMediaTrack.getConstraints(), props);
|
|
@@ -311,64 +332,33 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
|
|
|
311
332
|
}, 'Video processing is skipped');
|
|
312
333
|
return prevMediaTrack;
|
|
313
334
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (props.transformer.segmenter.status === 'new') {
|
|
324
|
-
await props.videoProcessor().open({
|
|
325
|
-
processingWidth: width,
|
|
326
|
-
processingHeight: height,
|
|
327
|
-
});
|
|
328
|
-
props.transformer.backend = gpuAPI();
|
|
329
|
-
}
|
|
330
|
-
else {
|
|
331
|
-
props.transformer.update({
|
|
332
|
-
processingWidth: width,
|
|
333
|
-
processingHeight: height,
|
|
334
|
-
});
|
|
335
|
-
if (props.backgroundBlurAmount !== undefined) {
|
|
336
|
-
props.transformer.backgroundBlurAmount =
|
|
337
|
-
getBlurKernelSize(props.backgroundBlurAmount, referenceProcessingHeight ??
|
|
338
|
-
processingHeight, height);
|
|
339
|
-
}
|
|
340
|
-
if (props.lightWrapBlurAmount !== undefined) {
|
|
341
|
-
props.transformer.lightWrapBlurAmount =
|
|
342
|
-
getBlurKernelSize(props.lightWrapBlurAmount, referenceProcessingHeight ??
|
|
343
|
-
processingHeight, height);
|
|
344
|
-
}
|
|
345
|
-
if (props.edgeBlurAmount !== undefined) {
|
|
346
|
-
props.transformer.edgeBlurAmount = getTentBlurSize(props.edgeBlurAmount, referenceProcessingHeight ?? processingHeight, height);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
335
|
+
const { videoSegmentation, ...renderOptions } = props;
|
|
336
|
+
const videoProcessor = proxyWithLog(logger, label)(getVideoProcessor(), 'VideoProcessor');
|
|
337
|
+
if (dynamicProcessingDimensions()) {
|
|
338
|
+
const { width, height } = prevMediaTrack.getSettings();
|
|
339
|
+
if (props.backgroundBlurAmount !== undefined) {
|
|
340
|
+
renderOptions.backgroundBlurAmount = getBlurKernelSize(props.backgroundBlurAmount, referenceProcessingHeight ?? processingHeight, height ?? processingHeight);
|
|
341
|
+
}
|
|
342
|
+
if (props.lightWrapBlurAmount !== undefined) {
|
|
343
|
+
renderOptions.lightWrapBlurAmount = getBlurKernelSize(props.lightWrapBlurAmount, referenceProcessingHeight ?? processingHeight, height ?? processingHeight);
|
|
350
344
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
props.transformer.backend = gpuAPI();
|
|
345
|
+
if (props.edgeBlurAmount !== undefined) {
|
|
346
|
+
renderOptions.edgeBlurAmount = getTentBlurSize(props.edgeBlurAmount, referenceProcessingHeight ?? processingHeight, height ?? processingHeight);
|
|
354
347
|
}
|
|
355
|
-
|
|
348
|
+
await videoProcessor.update({
|
|
349
|
+
processingWidth: width,
|
|
350
|
+
processingHeight: height,
|
|
351
|
+
renderOptions: {
|
|
352
|
+
backend: gpuAPI(),
|
|
353
|
+
...renderOptions,
|
|
354
|
+
effects: videoSegmentation,
|
|
355
|
+
},
|
|
356
|
+
});
|
|
356
357
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
props.segmenters[features.videoSegmentationModel];
|
|
360
|
-
if (features.videoSegmentationModel &&
|
|
361
|
-
features.videoSegmentationModel !==
|
|
362
|
-
props.transformer.segmenter.modelAsset.modelName &&
|
|
363
|
-
model) {
|
|
364
|
-
props.transformer.segmenter = model;
|
|
358
|
+
else {
|
|
359
|
+
await applyFeatures(videoProcessor, { ...features, videoSegmentation }, referenceProcessingHeight);
|
|
365
360
|
}
|
|
366
|
-
const
|
|
367
|
-
.videoProcessor()
|
|
368
|
-
// FIXME: Change process to accept MediaStreamTrack instead of MediaStream
|
|
369
|
-
.process(new MediaStream([prevMediaTrack.track]));
|
|
370
|
-
const track = stream.getVideoTracks().at(0);
|
|
371
|
-
assert(track, 'Video track should be there');
|
|
361
|
+
const track = await videoProcessor.process(prevMediaTrack.track);
|
|
372
362
|
// Inherit contentHint from previous track
|
|
373
363
|
track.contentHint = prevMediaTrack.track.contentHint;
|
|
374
364
|
let trackReleaseTimeoutID = 0;
|
|
@@ -393,18 +383,15 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
|
|
|
393
383
|
return this.previousMediaTrack?.muted;
|
|
394
384
|
},
|
|
395
385
|
mute(mute, _self, soft) {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
: props.videoSegmentation ?? 'none';
|
|
399
|
-
muteStreamTrack(stream)(mute, 'video');
|
|
386
|
+
videoProcessor.mute(mute);
|
|
387
|
+
track.enabled = !mute;
|
|
400
388
|
if (stopAsMute() && !soft) {
|
|
401
389
|
if (mute) {
|
|
402
390
|
// Track cannot be stopped immediately as we need to ensure
|
|
403
391
|
// the last frame is black to avoid frozen frame in a gateway call
|
|
404
392
|
trackReleaseTimeoutID = window.setTimeout(() => {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
393
|
+
track.stop();
|
|
394
|
+
videoProcessor.close();
|
|
408
395
|
void this?.release?.();
|
|
409
396
|
trackReleaseTimeoutID = 0;
|
|
410
397
|
}, 500);
|
|
@@ -420,10 +407,8 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
|
|
|
420
407
|
},
|
|
421
408
|
signals,
|
|
422
409
|
async release() {
|
|
423
|
-
|
|
410
|
+
videoProcessor.close();
|
|
424
411
|
await this.previousMediaTrack?.release();
|
|
425
|
-
_videoProcessor = undefined;
|
|
426
|
-
props.hasInitialized = false;
|
|
427
412
|
},
|
|
428
413
|
async applyConstraints(constraints) {
|
|
429
414
|
if (isEmpty(constraints)) {
|
|
@@ -434,69 +419,64 @@ label = PROCESSOR_LABELS.VideoProcessor, referenceProcessingHeight, maskCombineR
|
|
|
434
419
|
if (isEmpty(features)) {
|
|
435
420
|
return;
|
|
436
421
|
}
|
|
437
|
-
applyFeatures(
|
|
422
|
+
await applyFeatures(videoProcessor, features, referenceProcessingHeight);
|
|
438
423
|
if (dynamicProcessingDimensions()) {
|
|
439
424
|
const acceptedSettings = this.previousMediaTrack?.source.getSettings();
|
|
440
425
|
if (acceptedSettings?.width && acceptedSettings?.height) {
|
|
441
|
-
|
|
442
|
-
processingHeight: acceptedSettings.height,
|
|
443
|
-
processingWidth: acceptedSettings.width,
|
|
444
|
-
});
|
|
426
|
+
const renderOptions = {};
|
|
445
427
|
if (props.backgroundBlurAmount !== undefined) {
|
|
446
|
-
|
|
428
|
+
renderOptions.backgroundBlurAmount =
|
|
447
429
|
getBlurKernelSize(props.backgroundBlurAmount, referenceProcessingHeight ??
|
|
448
430
|
processingHeight, acceptedSettings.height);
|
|
449
431
|
}
|
|
450
432
|
if (props.lightWrapBlurAmount !== undefined) {
|
|
451
|
-
|
|
433
|
+
renderOptions.lightWrapBlurAmount =
|
|
452
434
|
getBlurKernelSize(props.lightWrapBlurAmount, referenceProcessingHeight ??
|
|
453
435
|
processingHeight, acceptedSettings.height);
|
|
454
436
|
}
|
|
455
437
|
if (props.edgeBlurAmount !== undefined) {
|
|
456
|
-
|
|
438
|
+
renderOptions.edgeBlurAmount = getTentBlurSize(props.edgeBlurAmount, referenceProcessingHeight ?? processingHeight, acceptedSettings.height);
|
|
457
439
|
}
|
|
440
|
+
await videoProcessor.update({
|
|
441
|
+
processingHeight: acceptedSettings.height,
|
|
442
|
+
processingWidth: acceptedSettings.width,
|
|
443
|
+
renderOptions,
|
|
444
|
+
});
|
|
458
445
|
}
|
|
459
446
|
}
|
|
460
|
-
const model = features.videoSegmentationModel &&
|
|
461
|
-
props.segmenters[features.videoSegmentationModel];
|
|
462
|
-
if (model &&
|
|
463
|
-
features.videoSegmentationModel !==
|
|
464
|
-
props.transformer.segmenter.modelAsset.modelName) {
|
|
465
|
-
props.transformer.segmenter = model;
|
|
466
|
-
}
|
|
467
447
|
},
|
|
468
448
|
getSettings: () => {
|
|
469
449
|
const contentHint = track.contentHint ?? '';
|
|
450
|
+
const ro = videoProcessor.renderOptions;
|
|
470
451
|
return {
|
|
471
452
|
backgroundBlurAmount: props.backgroundBlurAmount,
|
|
472
|
-
backgroundImageUrl:
|
|
473
|
-
backgroundThreshold:
|
|
453
|
+
backgroundImageUrl: ro.backgroundImageUrl,
|
|
454
|
+
backgroundThreshold: ro.backgroundThreshold,
|
|
474
455
|
contentHint,
|
|
475
|
-
downSampleFactor:
|
|
476
|
-
edgeBlurAmount:
|
|
477
|
-
excludeBystanders:
|
|
478
|
-
foregroundThreshold:
|
|
456
|
+
downSampleFactor: ro.downSampleFactor,
|
|
457
|
+
edgeBlurAmount: ro.edgeBlurAmount,
|
|
458
|
+
excludeBystanders: ro.excludeBystanders,
|
|
459
|
+
foregroundThreshold: ro.foregroundThreshold,
|
|
479
460
|
frameRate: props.frameRate,
|
|
480
461
|
height: props.height,
|
|
481
|
-
lightWrapBlurAmount:
|
|
482
|
-
lightWrapEdgeBand:
|
|
483
|
-
lightWrapIntensity:
|
|
484
|
-
lightWrapTightness:
|
|
485
|
-
maskCombineRatio:
|
|
486
|
-
morphDilateRadiusPx:
|
|
487
|
-
morphErodeRadiusPx:
|
|
488
|
-
morphPass:
|
|
489
|
-
|
|
490
|
-
personCenterX:
|
|
491
|
-
personCenterY:
|
|
492
|
-
sigmaRangeHi:
|
|
493
|
-
sigmaRangeLo:
|
|
494
|
-
sigmaSpace:
|
|
495
|
-
|
|
496
|
-
videoSegmentation:
|
|
497
|
-
videoSegmentationModel: transformer.segmenter.modelAsset.modelName,
|
|
462
|
+
lightWrapBlurAmount: ro.lightWrapBlurAmount,
|
|
463
|
+
lightWrapEdgeBand: ro.lightWrapEdgeBand,
|
|
464
|
+
lightWrapIntensity: ro.lightWrapIntensity,
|
|
465
|
+
lightWrapTightness: ro.lightWrapTightness,
|
|
466
|
+
maskCombineRatio: ro.maskCombineRatio,
|
|
467
|
+
morphDilateRadiusPx: ro.morphDilateRadiusPx,
|
|
468
|
+
morphErodeRadiusPx: ro.morphErodeRadiusPx,
|
|
469
|
+
morphPass: ro.morphPass,
|
|
470
|
+
panEnabled: props.pan,
|
|
471
|
+
personCenterX: ro.personCenter[0],
|
|
472
|
+
personCenterY: ro.personCenter[1],
|
|
473
|
+
sigmaRangeHi: ro.sigmaRangeHi,
|
|
474
|
+
sigmaRangeLo: ro.sigmaRangeLo,
|
|
475
|
+
sigmaSpace: ro.sigmaSpace,
|
|
476
|
+
tiltEnabled: props.tilt,
|
|
477
|
+
videoSegmentation: ro.effects,
|
|
498
478
|
width: props.width,
|
|
499
|
-
|
|
479
|
+
zoomEnabled: props.zoom,
|
|
500
480
|
};
|
|
501
481
|
},
|
|
502
482
|
});
|