|
@@ -17,7 +17,7 @@ import {
|
17
|
17
|
export default class JitsiStreamBackgroundEffect {
|
18
|
18
|
_model: Object;
|
19
|
19
|
_options: Object;
|
20
|
|
- _desktopShareDimensions: Object;
|
|
20
|
+ _stream: Object;
|
21
|
21
|
_segmentationPixelCount: number;
|
22
|
22
|
_inputVideoElement: HTMLVideoElement;
|
23
|
23
|
_onMaskFrameTimer: Function;
|
|
@@ -85,6 +85,12 @@ export default class JitsiStreamBackgroundEffect {
|
85
|
85
|
* @returns {void}
|
86
|
86
|
*/
|
87
|
87
|
runPostProcessing() {
|
|
88
|
+
|
|
89
|
+ const track = this._stream.getVideoTracks()[0];
|
|
90
|
+ const { height, width } = track.getSettings() ?? track.getConstraints();
|
|
91
|
+
|
|
92
|
+ this._outputCanvasElement.height = height;
|
|
93
|
+ this._outputCanvasElement.width = width;
|
88
|
94
|
this._outputCanvasCtx.globalCompositeOperation = 'copy';
|
89
|
95
|
|
90
|
96
|
// Draw segmentation mask.
|
|
@@ -130,13 +136,23 @@ export default class JitsiStreamBackgroundEffect {
|
130
|
136
|
);
|
131
|
137
|
}
|
132
|
138
|
if (this._options.virtualBackground.backgroundType === VIRTUAL_BACKGROUND_TYPE.DESKTOP_SHARE) {
|
|
139
|
+
|
|
140
|
+ // save current context before applying transformations
|
|
141
|
+ this._outputCanvasCtx.save();
|
|
142
|
+
|
|
143
|
+ // flip the canvas and prevent mirror behaviour
|
|
144
|
+ this._outputCanvasCtx.scale(-1, 1);
|
|
145
|
+ this._outputCanvasCtx.translate(-this._outputCanvasElement.width, 0);
|
133
|
146
|
this._outputCanvasCtx.drawImage(
|
134
|
147
|
this._virtualVideo,
|
135
|
148
|
0,
|
136
|
149
|
0,
|
137
|
|
- this._desktopShareDimensions.width,
|
138
|
|
- this._desktopShareDimensions.height
|
|
150
|
+ this._outputCanvasElement.width,
|
|
151
|
+ this._outputCanvasElement.height
|
139
|
152
|
);
|
|
153
|
+
|
|
154
|
+ // restore the canvas
|
|
155
|
+ this._outputCanvasCtx.restore();
|
140
|
156
|
} else {
|
141
|
157
|
this._outputCanvasCtx.filter = `blur(${this._options.virtualBackground.blurValue}px)`;
|
142
|
158
|
this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
|
|
@@ -172,12 +188,6 @@ export default class JitsiStreamBackgroundEffect {
|
172
|
188
|
* @returns {void}
|
173
|
189
|
*/
|
174
|
190
|
_renderMask() {
|
175
|
|
- const desktopShareTrack = this._options?.virtualBackground?.virtualSource?.track;
|
176
|
|
-
|
177
|
|
- if (desktopShareTrack) {
|
178
|
|
- this._desktopShareDimensions = desktopShareTrack.getSettings ? desktopShareTrack.getSettings()
|
179
|
|
- : desktopShareTrack.getConstraints();
|
180
|
|
- }
|
181
|
191
|
this.resizeSource();
|
182
|
192
|
this.runInference();
|
183
|
193
|
this.runPostProcessing();
|
|
@@ -239,9 +249,10 @@ export default class JitsiStreamBackgroundEffect {
|
239
|
249
|
* @returns {MediaStream} - The stream with the applied effect.
|
240
|
250
|
*/
|
241
|
251
|
startEffect(stream: MediaStream) {
|
|
252
|
+ this._stream = stream;
|
242
|
253
|
this._maskFrameTimerWorker = new Worker(timerWorkerScript, { name: 'Blur effect worker' });
|
243
|
254
|
this._maskFrameTimerWorker.onmessage = this._onMaskFrameTimer;
|
244
|
|
- const firstVideoTrack = stream.getVideoTracks()[0];
|
|
255
|
+ const firstVideoTrack = this._stream.getVideoTracks()[0];
|
245
|
256
|
const { height, frameRate, width }
|
246
|
257
|
= firstVideoTrack.getSettings ? firstVideoTrack.getSettings() : firstVideoTrack.getConstraints();
|
247
|
258
|
|
|
@@ -257,7 +268,7 @@ export default class JitsiStreamBackgroundEffect {
|
257
|
268
|
this._inputVideoElement.width = parseInt(width, 10);
|
258
|
269
|
this._inputVideoElement.height = parseInt(height, 10);
|
259
|
270
|
this._inputVideoElement.autoplay = true;
|
260
|
|
- this._inputVideoElement.srcObject = stream;
|
|
271
|
+ this._inputVideoElement.srcObject = this._stream;
|
261
|
272
|
this._inputVideoElement.onloadeddata = () => {
|
262
|
273
|
this._maskFrameTimerWorker.postMessage({
|
263
|
274
|
id: SET_TIMEOUT,
|