@pexip/media 20.1.0 → 20.3.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 +79 -0
- package/dist/audioMixingProcessor.d.ts +3 -3
- package/dist/audioMixingProcessor.js +7 -6
- package/dist/audioProcessor.d.ts +5 -4
- package/dist/audioProcessor.js +13 -9
- package/dist/media.d.ts +1 -1
- package/dist/media.js +74 -65
- package/dist/previewController.d.ts +29 -7
- package/dist/previewController.js +118 -19
- package/dist/types.d.ts +51 -48
- package/dist/userMedia.d.ts +9 -4
- package/dist/userMedia.js +67 -21
- package/dist/utils.d.ts +3 -1
- package/dist/utils.js +177 -116
- package/dist/videoProcessor.d.ts +8 -5
- package/dist/videoProcessor.js +94 -53
- package/package.json +6 -6
- package/dist/tsconfig.build.tsbuildinfo +0 -1
package/dist/videoProcessor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { createCanvasTransform, createVideoProcessor, createVideoTrackProcessor, createVideoTrackProcessorWithFallback, isRenderEffects, isSegmentationModel, } from '@pexip/media-processor';
|
|
2
|
+
import { extractConstraintsWithKeys, getValueFromConstrainNumber, muteStreamTrack, } from '@pexip/media-control';
|
|
3
3
|
import { isEmpty, assert } from '@pexip/utils';
|
|
4
4
|
import { createMediaTrack, getBlurKernelSize } from './utils';
|
|
5
5
|
import { logger, proxyWithLog } from './logger';
|
|
@@ -94,7 +94,7 @@ export const updateFeatureProps = (constraints, props) => {
|
|
|
94
94
|
}
|
|
95
95
|
}, {});
|
|
96
96
|
};
|
|
97
|
-
const applyFeatures = (transformer, features) => {
|
|
97
|
+
const applyFeatures = (transformer, features, lowestProcessingHeight) => {
|
|
98
98
|
for (const key in features) {
|
|
99
99
|
const k = key;
|
|
100
100
|
switch (k) {
|
|
@@ -110,7 +110,7 @@ const applyFeatures = (transformer, features) => {
|
|
|
110
110
|
case 'backgroundBlurAmount': {
|
|
111
111
|
const value = features[k];
|
|
112
112
|
if (value !== undefined) {
|
|
113
|
-
transformer[k] = getBlurKernelSize(value, transformer.height);
|
|
113
|
+
transformer[k] = getBlurKernelSize(value, transformer.height, lowestProcessingHeight);
|
|
114
114
|
}
|
|
115
115
|
break;
|
|
116
116
|
}
|
|
@@ -141,19 +141,15 @@ const getTrackProcessor = (shouldUseStreamTrackProcessor, ...params) => {
|
|
|
141
141
|
}
|
|
142
142
|
return createVideoTrackProcessorWithFallback(...params);
|
|
143
143
|
};
|
|
144
|
-
export const createVideoStreamProcess = ({
|
|
145
|
-
|
|
146
|
-
videoSegmentation,
|
|
147
|
-
//edgeBlurAmount,
|
|
148
|
-
foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label = PROCESSOR_LABELS.VideoProcessor, dynamicProcessingDimensions = () => false, gpuAPI = () => 'webgl', // dynamically changing the config will not be picked up, not a priority for now
|
|
149
|
-
...options }) => {
|
|
144
|
+
export const createVideoStreamProcess = ({ backgroundImageUrl, dynamicProcessingDimensions = () => false, edgeBlurAmount, foregroundThreshold, frameRate, gpuAPI = () => 'webgl', // dynamically changing the config will not be picked up, not a priority for now
|
|
145
|
+
label = PROCESSOR_LABELS.VideoProcessor, lowestProcessingHeight, maskCombineRatio, processingHeight, processingWidth, shouldEnable, stopAsMute = () => false, trackProcessorAPI = () => 'stream', videoSegmentation, signals, ...options }) => {
|
|
150
146
|
const videoSegmentationModel = options.videoSegmentationModel ?? 'selfie';
|
|
151
147
|
const segmenter = options.segmenters[videoSegmentationModel];
|
|
152
148
|
if (!segmenter) {
|
|
153
149
|
throw new Error('Segmenter is undefined');
|
|
154
150
|
}
|
|
155
151
|
const backgroundBlurAmount = options.backgroundBlurAmount &&
|
|
156
|
-
getBlurKernelSize(options.backgroundBlurAmount, processingHeight);
|
|
152
|
+
getBlurKernelSize(options.backgroundBlurAmount, processingHeight, lowestProcessingHeight);
|
|
157
153
|
const transformer = options.transformer ??
|
|
158
154
|
createCanvasTransform(segmenter, {
|
|
159
155
|
width: processingWidth,
|
|
@@ -199,29 +195,39 @@ foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label
|
|
|
199
195
|
const features = updateFeatureProps(prevMediaTrack.getConstraints(), props);
|
|
200
196
|
const shouldEnabled = shouldEnable();
|
|
201
197
|
if (!shouldEnabled || !prevMediaTrack.track) {
|
|
202
|
-
logger.debug({
|
|
198
|
+
logger.debug({
|
|
199
|
+
label,
|
|
200
|
+
features,
|
|
201
|
+
shouldEnabled,
|
|
202
|
+
}, 'Video processing is skipped');
|
|
203
203
|
return prevMediaTrack;
|
|
204
204
|
}
|
|
205
205
|
if (!props.hasInitialized) {
|
|
206
206
|
if (dynamicProcessingDimensions()) {
|
|
207
207
|
const { width, height } = prevMediaTrack.getSettings();
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
208
|
+
if (width && height) {
|
|
209
|
+
/**
|
|
210
|
+
* when the processor is closed, the segmenter is not killed, but the track is released.
|
|
211
|
+
* this means we can't listen on the track settings changes when we change quality
|
|
212
|
+
* we need to update instead of open if the segmenter is already running
|
|
213
|
+
*/
|
|
214
|
+
if (props.transformer.segmenter.status === 'new') {
|
|
215
|
+
await props.videoProcessor().open({
|
|
216
|
+
processingWidth: width,
|
|
217
|
+
processingHeight: height,
|
|
218
|
+
});
|
|
219
|
+
props.transformer.backend = gpuAPI();
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
props.transformer.update({
|
|
223
|
+
processingWidth: width,
|
|
224
|
+
processingHeight: height,
|
|
225
|
+
});
|
|
226
|
+
if (props.backgroundBlurAmount !== undefined) {
|
|
227
|
+
props.transformer.backgroundBlurAmount =
|
|
228
|
+
getBlurKernelSize(props.backgroundBlurAmount, height, lowestProcessingHeight);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
225
231
|
}
|
|
226
232
|
}
|
|
227
233
|
else {
|
|
@@ -230,7 +236,7 @@ foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label
|
|
|
230
236
|
}
|
|
231
237
|
props.hasInitialized = true;
|
|
232
238
|
}
|
|
233
|
-
applyFeatures(props.transformer, features);
|
|
239
|
+
applyFeatures(props.transformer, features, lowestProcessingHeight);
|
|
234
240
|
const model = features.videoSegmentationModel &&
|
|
235
241
|
props.segmenters[features.videoSegmentationModel];
|
|
236
242
|
if (features.videoSegmentationModel &&
|
|
@@ -247,30 +253,61 @@ foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label
|
|
|
247
253
|
assert(track, 'Video track should be there');
|
|
248
254
|
// Inherit contentHint from previous track
|
|
249
255
|
track.contentHint = prevMediaTrack.track.contentHint;
|
|
250
|
-
|
|
251
|
-
props.videoProcessor().close();
|
|
252
|
-
await prevMediaTrack.release();
|
|
253
|
-
_videoProcessor = undefined;
|
|
254
|
-
props.hasInitialized = false;
|
|
255
|
-
};
|
|
256
|
-
const mute = (mute) => {
|
|
257
|
-
props.transformer.effects = mute
|
|
258
|
-
? 'none'
|
|
259
|
-
: props.videoSegmentation ?? 'none';
|
|
260
|
-
prevMediaTrack.mute(mute);
|
|
261
|
-
muteStreamTrack(stream)(mute, 'video');
|
|
262
|
-
};
|
|
256
|
+
let trackReleaseTimeoutID = 0;
|
|
263
257
|
return createMediaTrack({
|
|
264
258
|
label,
|
|
265
259
|
kind: 'videoinput',
|
|
266
|
-
constraints
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
260
|
+
get constraints() {
|
|
261
|
+
return this.previousMediaTrack?.getConstraints();
|
|
262
|
+
},
|
|
263
|
+
get previousMediaTrack() {
|
|
264
|
+
return prevMediaTrack;
|
|
265
|
+
},
|
|
266
|
+
get input() {
|
|
267
|
+
return this.previousMediaTrack?.input;
|
|
268
|
+
},
|
|
269
|
+
get expectedInput() {
|
|
270
|
+
return this.previousMediaTrack?.expectedInput;
|
|
271
|
+
},
|
|
270
272
|
track,
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
273
|
+
overrideMute: true,
|
|
274
|
+
get muted() {
|
|
275
|
+
return this.previousMediaTrack?.muted;
|
|
276
|
+
},
|
|
277
|
+
mute(mute, _self, soft) {
|
|
278
|
+
props.transformer.effects = mute
|
|
279
|
+
? 'none'
|
|
280
|
+
: props.videoSegmentation ?? 'none';
|
|
281
|
+
muteStreamTrack(stream)(mute, 'video');
|
|
282
|
+
if (stopAsMute() && !soft) {
|
|
283
|
+
if (mute) {
|
|
284
|
+
// Track cannot be stopped immediately as we need to ensure
|
|
285
|
+
// the last frame is black to avoid frozen frame in a gateway call
|
|
286
|
+
trackReleaseTimeoutID = window.setTimeout(() => {
|
|
287
|
+
for (const track of stream.getVideoTracks()) {
|
|
288
|
+
track.stop();
|
|
289
|
+
}
|
|
290
|
+
void this?.release?.();
|
|
291
|
+
trackReleaseTimeoutID = 0;
|
|
292
|
+
}, 500);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
if (trackReleaseTimeoutID) {
|
|
296
|
+
window.clearTimeout(trackReleaseTimeoutID);
|
|
297
|
+
trackReleaseTimeoutID = 0;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
this.previousMediaTrack?.mute(mute, soft);
|
|
302
|
+
},
|
|
303
|
+
signals,
|
|
304
|
+
async release() {
|
|
305
|
+
props.videoProcessor().close();
|
|
306
|
+
await this.previousMediaTrack?.release();
|
|
307
|
+
_videoProcessor = undefined;
|
|
308
|
+
props.hasInitialized = false;
|
|
309
|
+
},
|
|
310
|
+
async applyConstraints(constraints) {
|
|
274
311
|
if (isEmpty(constraints)) {
|
|
275
312
|
return;
|
|
276
313
|
}
|
|
@@ -279,14 +316,18 @@ foregroundThreshold, backgroundImageUrl, maskCombineRatio, edgeBlurAmount, label
|
|
|
279
316
|
if (isEmpty(features)) {
|
|
280
317
|
return;
|
|
281
318
|
}
|
|
282
|
-
applyFeatures(props.transformer, features);
|
|
319
|
+
applyFeatures(props.transformer, features, lowestProcessingHeight);
|
|
283
320
|
if (dynamicProcessingDimensions()) {
|
|
284
|
-
const acceptedSettings =
|
|
285
|
-
if (acceptedSettings
|
|
321
|
+
const acceptedSettings = this.previousMediaTrack?.source.getSettings();
|
|
322
|
+
if (acceptedSettings?.width && acceptedSettings?.height) {
|
|
286
323
|
props.transformer.update({
|
|
287
324
|
processingHeight: acceptedSettings.height,
|
|
288
325
|
processingWidth: acceptedSettings.width,
|
|
289
326
|
});
|
|
327
|
+
if (props.backgroundBlurAmount !== undefined) {
|
|
328
|
+
props.transformer.backgroundBlurAmount =
|
|
329
|
+
getBlurKernelSize(props.backgroundBlurAmount, acceptedSettings.height, lowestProcessingHeight);
|
|
330
|
+
}
|
|
290
331
|
}
|
|
291
332
|
}
|
|
292
333
|
const model = features.videoSegmentationModel &&
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pexip/media",
|
|
3
|
-
"version": "20.
|
|
3
|
+
"version": "20.3.0",
|
|
4
4
|
"description": "Home for media related stuff",
|
|
5
5
|
"homepage": "https://gitlab.com/pexip/zoo",
|
|
6
6
|
"bugs": "https://gitlab.com/pexip/zoo/issues",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
"typecheck": "yarn tsc --noEmit -p ."
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@pexip/media-control": "20.
|
|
48
|
-
"@pexip/media-processor": "20.
|
|
49
|
-
"@pexip/signal": "16.
|
|
50
|
-
"@pexip/utils": "17.0.
|
|
47
|
+
"@pexip/media-control": "20.3.0",
|
|
48
|
+
"@pexip/media-processor": "20.3.0",
|
|
49
|
+
"@pexip/signal": "16.9.0",
|
|
50
|
+
"@pexip/utils": "17.0.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@jest/globals": "^29.7.0",
|
|
54
|
-
"@pexip/bundler": "18.1.
|
|
54
|
+
"@pexip/bundler": "18.1.2",
|
|
55
55
|
"@swc/core": "^1.10.12",
|
|
56
56
|
"@swc/jest": "^0.2.37",
|
|
57
57
|
"jest": "^29.5.12",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"root":["../src/audioMixingProcessor.ts","../src/audioProcessor.ts","../src/baseLogger.ts","../src/constants.ts","../src/displayMedia.ts","../src/index.ts","../src/logger.ts","../src/media.ts","../src/previewController.ts","../src/signals.ts","../src/status.ts","../src/typeGuard.ts","../src/types.ts","../src/userMedia.ts","../src/utils.ts","../src/videoProcessor.ts","../../../@types/globals.d.ts"],"version":"5.7.3"}
|