fix(virtual-background): Fix resize action and prevent mirror behavio… (#9441)
* fix(virtual-background): Fix resize action and prevent mirror behaviour on desktop share as a virtual background. Co-authored-by: tudordan7 <tudor.pop@decagon.tech>
This commit is contained in:
parent
1d45edbb27
commit
74d65ff596
|
@ -17,7 +17,7 @@ import {
|
||||||
export default class JitsiStreamBackgroundEffect {
|
export default class JitsiStreamBackgroundEffect {
|
||||||
_model: Object;
|
_model: Object;
|
||||||
_options: Object;
|
_options: Object;
|
||||||
_desktopShareDimensions: Object;
|
_stream: Object;
|
||||||
_segmentationPixelCount: number;
|
_segmentationPixelCount: number;
|
||||||
_inputVideoElement: HTMLVideoElement;
|
_inputVideoElement: HTMLVideoElement;
|
||||||
_onMaskFrameTimer: Function;
|
_onMaskFrameTimer: Function;
|
||||||
|
@ -85,6 +85,12 @@ export default class JitsiStreamBackgroundEffect {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
runPostProcessing() {
|
runPostProcessing() {
|
||||||
|
|
||||||
|
const track = this._stream.getVideoTracks()[0];
|
||||||
|
const { height, width } = track.getSettings() ?? track.getConstraints();
|
||||||
|
|
||||||
|
this._outputCanvasElement.height = height;
|
||||||
|
this._outputCanvasElement.width = width;
|
||||||
this._outputCanvasCtx.globalCompositeOperation = 'copy';
|
this._outputCanvasCtx.globalCompositeOperation = 'copy';
|
||||||
|
|
||||||
// Draw segmentation mask.
|
// Draw segmentation mask.
|
||||||
|
@ -130,13 +136,23 @@ export default class JitsiStreamBackgroundEffect {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this._options.virtualBackground.backgroundType === VIRTUAL_BACKGROUND_TYPE.DESKTOP_SHARE) {
|
if (this._options.virtualBackground.backgroundType === VIRTUAL_BACKGROUND_TYPE.DESKTOP_SHARE) {
|
||||||
|
|
||||||
|
// save current context before applying transformations
|
||||||
|
this._outputCanvasCtx.save();
|
||||||
|
|
||||||
|
// flip the canvas and prevent mirror behaviour
|
||||||
|
this._outputCanvasCtx.scale(-1, 1);
|
||||||
|
this._outputCanvasCtx.translate(-this._outputCanvasElement.width, 0);
|
||||||
this._outputCanvasCtx.drawImage(
|
this._outputCanvasCtx.drawImage(
|
||||||
this._virtualVideo,
|
this._virtualVideo,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
this._desktopShareDimensions.width,
|
this._outputCanvasElement.width,
|
||||||
this._desktopShareDimensions.height
|
this._outputCanvasElement.height
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// restore the canvas
|
||||||
|
this._outputCanvasCtx.restore();
|
||||||
} else {
|
} else {
|
||||||
this._outputCanvasCtx.filter = `blur(${this._options.virtualBackground.blurValue}px)`;
|
this._outputCanvasCtx.filter = `blur(${this._options.virtualBackground.blurValue}px)`;
|
||||||
this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
|
this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
|
||||||
|
@ -172,12 +188,6 @@ export default class JitsiStreamBackgroundEffect {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
_renderMask() {
|
_renderMask() {
|
||||||
const desktopShareTrack = this._options?.virtualBackground?.virtualSource?.track;
|
|
||||||
|
|
||||||
if (desktopShareTrack) {
|
|
||||||
this._desktopShareDimensions = desktopShareTrack.getSettings ? desktopShareTrack.getSettings()
|
|
||||||
: desktopShareTrack.getConstraints();
|
|
||||||
}
|
|
||||||
this.resizeSource();
|
this.resizeSource();
|
||||||
this.runInference();
|
this.runInference();
|
||||||
this.runPostProcessing();
|
this.runPostProcessing();
|
||||||
|
@ -239,9 +249,10 @@ export default class JitsiStreamBackgroundEffect {
|
||||||
* @returns {MediaStream} - The stream with the applied effect.
|
* @returns {MediaStream} - The stream with the applied effect.
|
||||||
*/
|
*/
|
||||||
startEffect(stream: MediaStream) {
|
startEffect(stream: MediaStream) {
|
||||||
|
this._stream = stream;
|
||||||
this._maskFrameTimerWorker = new Worker(timerWorkerScript, { name: 'Blur effect worker' });
|
this._maskFrameTimerWorker = new Worker(timerWorkerScript, { name: 'Blur effect worker' });
|
||||||
this._maskFrameTimerWorker.onmessage = this._onMaskFrameTimer;
|
this._maskFrameTimerWorker.onmessage = this._onMaskFrameTimer;
|
||||||
const firstVideoTrack = stream.getVideoTracks()[0];
|
const firstVideoTrack = this._stream.getVideoTracks()[0];
|
||||||
const { height, frameRate, width }
|
const { height, frameRate, width }
|
||||||
= firstVideoTrack.getSettings ? firstVideoTrack.getSettings() : firstVideoTrack.getConstraints();
|
= firstVideoTrack.getSettings ? firstVideoTrack.getSettings() : firstVideoTrack.getConstraints();
|
||||||
|
|
||||||
|
@ -257,7 +268,7 @@ export default class JitsiStreamBackgroundEffect {
|
||||||
this._inputVideoElement.width = parseInt(width, 10);
|
this._inputVideoElement.width = parseInt(width, 10);
|
||||||
this._inputVideoElement.height = parseInt(height, 10);
|
this._inputVideoElement.height = parseInt(height, 10);
|
||||||
this._inputVideoElement.autoplay = true;
|
this._inputVideoElement.autoplay = true;
|
||||||
this._inputVideoElement.srcObject = stream;
|
this._inputVideoElement.srcObject = this._stream;
|
||||||
this._inputVideoElement.onloadeddata = () => {
|
this._inputVideoElement.onloadeddata = () => {
|
||||||
this._maskFrameTimerWorker.postMessage({
|
this._maskFrameTimerWorker.postMessage({
|
||||||
id: SET_TIMEOUT,
|
id: SET_TIMEOUT,
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { browser, JitsiTrackErrors } from '../../base/lib-jitsi-meet';
|
||||||
import { createLocalTrack } from '../../base/lib-jitsi-meet/functions';
|
import { createLocalTrack } from '../../base/lib-jitsi-meet/functions';
|
||||||
import { VIDEO_TYPE } from '../../base/media';
|
import { VIDEO_TYPE } from '../../base/media';
|
||||||
import { connect } from '../../base/redux';
|
import { connect } from '../../base/redux';
|
||||||
|
import { updateSettings } from '../../base/settings';
|
||||||
import { Tooltip } from '../../base/tooltip';
|
import { Tooltip } from '../../base/tooltip';
|
||||||
import { getLocalVideoTrack } from '../../base/tracks';
|
import { getLocalVideoTrack } from '../../base/tracks';
|
||||||
import { showErrorNotification } from '../../notifications';
|
import { showErrorNotification } from '../../notifications';
|
||||||
|
@ -73,6 +74,11 @@ const images: Array<Image> = [
|
||||||
];
|
];
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current local flip x status.
|
||||||
|
*/
|
||||||
|
_localFlipX: boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the jitsi track that will have backgraund effect applied.
|
* Returns the jitsi track that will have backgraund effect applied.
|
||||||
*/
|
*/
|
||||||
|
@ -121,7 +127,10 @@ const onError = event => {
|
||||||
* @returns {{Props}}
|
* @returns {{Props}}
|
||||||
*/
|
*/
|
||||||
function _mapStateToProps(state): Object {
|
function _mapStateToProps(state): Object {
|
||||||
|
const { localFlipX } = state['features/base/settings'];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
_localFlipX: Boolean(localFlipX),
|
||||||
_virtualBackground: state['features/virtual-background'],
|
_virtualBackground: state['features/virtual-background'],
|
||||||
_selectedThumbnail: state['features/virtual-background'].selectedThumbnail,
|
_selectedThumbnail: state['features/virtual-background'].selectedThumbnail,
|
||||||
_jitsiTrack: getLocalVideoTrack(state['features/base/tracks'])?.jitsiTrack
|
_jitsiTrack: getLocalVideoTrack(state['features/base/tracks'])?.jitsiTrack
|
||||||
|
@ -136,6 +145,7 @@ const VirtualBackgroundDialog = translate(connect(_mapStateToProps)(VirtualBackg
|
||||||
* @returns {ReactElement}
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
function VirtualBackground({
|
function VirtualBackground({
|
||||||
|
_localFlipX,
|
||||||
_jitsiTrack,
|
_jitsiTrack,
|
||||||
_selectedThumbnail,
|
_selectedThumbnail,
|
||||||
_virtualBackground,
|
_virtualBackground,
|
||||||
|
@ -178,7 +188,12 @@ function VirtualBackground({
|
||||||
if (storedImages.length === backgroundsLimit) {
|
if (storedImages.length === backgroundsLimit) {
|
||||||
setStoredImages(storedImages.slice(1));
|
setStoredImages(storedImages.slice(1));
|
||||||
}
|
}
|
||||||
}, [ storedImages ]);
|
if (!_localFlipX) {
|
||||||
|
dispatch(updateSettings({
|
||||||
|
localFlipX: !_localFlipX
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}, [ storedImages, _localFlipX ]);
|
||||||
|
|
||||||
|
|
||||||
const enableBlur = useCallback(async () => {
|
const enableBlur = useCallback(async () => {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { toggleBackgroundEffect } from '../actions';
|
||||||
import { VIRTUAL_BACKGROUND_TYPE } from '../constants';
|
import { VIRTUAL_BACKGROUND_TYPE } from '../constants';
|
||||||
import { localTrackStopped } from '../functions';
|
import { localTrackStopped } from '../functions';
|
||||||
|
|
||||||
const videoClassName = 'video-preview-video';
|
const videoClassName = 'video-preview-video flipVideoX';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the React {@code PureComponent} props of {@link VirtualBackgroundPreview}.
|
* The type of the React {@code PureComponent} props of {@link VirtualBackgroundPreview}.
|
||||||
|
|
Loading…
Reference in New Issue