@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.
@@ -1,90 +1,93 @@
1
- import { createCanvasTransform, createVideoProcessor, createVideoTrackProcessor, createVideoTrackProcessorWithFallback, isRenderEffects, isSegmentationModel, } from '@pexip/media-processor';
2
- import { extractConstraintsWithKeys, getValueFromConstrainNumber, muteStreamTrack, } from '@pexip/media-control';
3
- import { isEmpty, assert } from '@pexip/utils';
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
- 'backgroundBlurAmount',
10
- 'backgroundImageUrl',
11
- 'backgroundThreshold',
12
- 'maskCombineRatio',
13
- 'edgeBlurAmount',
14
- 'foregroundThreshold',
15
- 'frameRate',
16
- 'videoSegmentation',
17
- 'videoSegmentationModel',
18
- 'width',
19
- 'height',
20
- 'pan',
21
- 'tilt',
22
- 'zoom',
23
- 'contentHint',
24
- 'sigmaSpace',
25
- 'sigmaRangeLo',
26
- 'sigmaRangeHi',
27
- 'excludeBystanders',
28
- 'personCenterX',
29
- 'personCenterY',
30
- 'morphErodeRadiusPx',
31
- 'morphPass',
32
- 'morphDilateRadiusPx',
33
- 'lightWrapIntensity',
34
- 'lightWrapTightness',
35
- 'lightWrapEdgeBand',
36
- 'lightWrapBlurAmount',
37
- 'downSampleFactor',
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 extracted = getVideoConstraints(constraints);
42
- return FEATURE_KEYS.reduce((accm, key) => {
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 = ''] = []] = extracted[key];
50
+ const [[feature = ''] = []] = extractConstraints(key)(constraints);
46
51
  if (isVideoContentHint(feature) && props[key] !== feature) {
47
52
  props[key] = feature;
48
- accm[key] = feature;
49
- return accm;
53
+ features[key] = feature;
50
54
  }
51
- return accm;
55
+ break;
52
56
  }
53
57
  case 'videoSegmentation': {
54
- const [[feature] = []] = extracted[key];
58
+ const [[feature] = []] = extractConstraints(key)(constraints);
55
59
  if (isRenderEffects(feature) && props[key] !== feature) {
56
60
  props[key] = feature;
57
- accm[key] = feature;
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
- return accm;
63
+ break;
70
64
  }
71
65
  case 'backgroundImageUrl': {
72
- const [[feature] = []] = extracted[key];
66
+ const [[feature] = []] = extractConstraints(key)(constraints);
73
67
  if (feature) {
74
68
  props[key] = feature;
75
- accm[key] = feature;
76
- return accm;
69
+ features[key] = feature;
77
70
  }
78
- return accm;
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] = extracted[key];
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
- accm[key] = value;
107
- return accm;
109
+ features[key] = value;
108
110
  }
109
111
  }
110
- return accm;
112
+ break;
111
113
  }
112
114
  case 'pan':
113
115
  case 'tilt':
114
116
  case 'zoom': {
115
- const [feature] = extracted[key];
117
+ const [feature] = extractConstraints(key)(constraints);
116
118
  if (feature !== undefined && props[key] !== feature) {
117
119
  props[key] = feature;
118
- accm[key] = feature;
119
- return accm;
120
+ features[key] = feature;
120
121
  }
121
- return accm;
122
+ break;
122
123
  }
123
124
  default:
124
- return accm;
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 = (transformer, features, referenceProcessingHeight) => {
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
- transformer[k] = value;
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
- transformer[k] = value;
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
- transformer.personCenter = [
235
+ renderOptions.personCenter = [
162
236
  value,
163
- transformer.personCenter[1],
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
- transformer.personCenter = [
172
- transformer.personCenter[0],
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
- transformer[k] = getBlurKernelSize(value, referenceProcessingHeight ?? transformer.height, transformer.height);
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
- transformer[k] = getTentBlurSize(value, referenceProcessingHeight ?? transformer.height, transformer.height);
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 !== transformer.effects) {
196
- transformer.effects = value;
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 && value !== transformer.backgroundImageUrl) {
203
- transformer.backgroundImageUrl = value;
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
- const getTrackProcessor = (shouldUseStreamTrackProcessor, ...params) => {
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, trackProcessorAPI = () => 'stream', videoSegmentation, signals, ...options }) => {
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
- if (!props.hasInitialized) {
315
- if (dynamicProcessingDimensions()) {
316
- const { width, height } = prevMediaTrack.getSettings();
317
- if (width && height) {
318
- /**
319
- * when the processor is closed, the segmenter is not killed, but the track is released.
320
- * this means we can't listen on the track settings changes when we change quality
321
- * we need to update instead of open if the segmenter is already running
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
- else {
352
- await props.videoProcessor().open();
353
- props.transformer.backend = gpuAPI();
345
+ if (props.edgeBlurAmount !== undefined) {
346
+ renderOptions.edgeBlurAmount = getTentBlurSize(props.edgeBlurAmount, referenceProcessingHeight ?? processingHeight, height ?? processingHeight);
354
347
  }
355
- props.hasInitialized = true;
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
- applyFeatures(props.transformer, features, referenceProcessingHeight);
358
- const model = features.videoSegmentationModel &&
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 stream = await props
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
- props.transformer.effects = mute
397
- ? 'none'
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
- for (const track of stream.getVideoTracks()) {
406
- track.stop();
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
- props.videoProcessor().close();
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(props.transformer, features, referenceProcessingHeight);
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
- props.transformer.update({
442
- processingHeight: acceptedSettings.height,
443
- processingWidth: acceptedSettings.width,
444
- });
426
+ const renderOptions = {};
445
427
  if (props.backgroundBlurAmount !== undefined) {
446
- props.transformer.backgroundBlurAmount =
428
+ renderOptions.backgroundBlurAmount =
447
429
  getBlurKernelSize(props.backgroundBlurAmount, referenceProcessingHeight ??
448
430
  processingHeight, acceptedSettings.height);
449
431
  }
450
432
  if (props.lightWrapBlurAmount !== undefined) {
451
- props.transformer.lightWrapBlurAmount =
433
+ renderOptions.lightWrapBlurAmount =
452
434
  getBlurKernelSize(props.lightWrapBlurAmount, referenceProcessingHeight ??
453
435
  processingHeight, acceptedSettings.height);
454
436
  }
455
437
  if (props.edgeBlurAmount !== undefined) {
456
- props.transformer.edgeBlurAmount = getTentBlurSize(props.edgeBlurAmount, referenceProcessingHeight ?? processingHeight, acceptedSettings.height);
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: transformer.backgroundImageUrl,
473
- backgroundThreshold: transformer.backgroundThreshold,
453
+ backgroundImageUrl: ro.backgroundImageUrl,
454
+ backgroundThreshold: ro.backgroundThreshold,
474
455
  contentHint,
475
- downSampleFactor: transformer.downSampleFactor,
476
- edgeBlurAmount: transformer.edgeBlurAmount,
477
- excludeBystanders: transformer.excludeBystanders,
478
- foregroundThreshold: transformer.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: transformer.lightWrapBlurAmount,
482
- lightWrapEdgeBand: transformer.lightWrapEdgeBand,
483
- lightWrapIntensity: transformer.lightWrapIntensity,
484
- lightWrapTightness: transformer.lightWrapTightness,
485
- maskCombineRatio: transformer.maskCombineRatio,
486
- morphDilateRadiusPx: transformer.morphDilateRadiusPx,
487
- morphErodeRadiusPx: transformer.morphErodeRadiusPx,
488
- morphPass: transformer.morphPass,
489
- pan: props.pan,
490
- personCenterX: transformer.personCenter[0],
491
- personCenterY: transformer.personCenter[1],
492
- sigmaRangeHi: transformer.sigmaRangeHi,
493
- sigmaRangeLo: transformer.sigmaRangeLo,
494
- sigmaSpace: transformer.sigmaSpace,
495
- tilt: props.tilt,
496
- videoSegmentation: transformer.effects,
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
- zoom: props.zoom,
479
+ zoomEnabled: props.zoom,
500
480
  };
501
481
  },
502
482
  });