feat(virtual-background) add slight blur option

This commit is contained in:
Tudor D. Pop 2021-04-09 15:17:06 +03:00 committed by GitHub
parent 927b40ec71
commit af28080058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 88 additions and 48 deletions

View File

@ -1,6 +1,6 @@
.virtual-background-dialog {
display: inline-grid;
grid-template-columns: auto auto auto auto auto auto auto;
grid-template-columns: auto auto auto auto auto auto auto auto;
max-width: 370px;
cursor: pointer;
.thumbnail {

View File

@ -339,7 +339,8 @@
},
"virtualBackground": {
"title": "Backgrounds",
"enableBlur": "Enable blur",
"blur": "Blur",
"slightBlur": "Slight Blur",
"removeBackground": "Remove background",
"uploadImage": "Upload image",
"pleaseWait": "Please wait...",

View File

@ -5,7 +5,6 @@ import {
SET_TIMEOUT,
timerWorkerScript
} from './TimerWorker';
const blurValue = '25px';
/**
* Represents a modified MediaStream that adds effects to video background.
@ -40,7 +39,7 @@ export default class JitsiStreamBackgroundEffect {
constructor(model: Object, options: Object) {
this._options = options;
if (this._options.virtualBackground.isVirtualBackground) {
if (this._options.virtualBackground.backgroundType === 'image') {
this._virtualImage = document.createElement('img');
this._virtualImage.crossOrigin = 'anonymous';
this._virtualImage.src = this._options.virtualBackground.virtualSource;
@ -65,9 +64,9 @@ export default class JitsiStreamBackgroundEffect {
* @param {EventHandler} response - The onmessage EventHandler parameter.
* @returns {void}
*/
async _onMaskFrameTimer(response: Object) {
_onMaskFrameTimer(response: Object) {
if (response.data.id === TIMEOUT_TICK) {
await this._renderMask();
this._renderMask();
}
}
@ -83,7 +82,7 @@ export default class JitsiStreamBackgroundEffect {
//
// Smooth out the edges.
if (this._options.virtualBackground.isVirtualBackground) {
if (this._options.virtualBackground.backgroundType === 'image') {
this._outputCanvasCtx.filter = 'blur(4px)';
} else {
this._outputCanvasCtx.filter = 'blur(8px)';
@ -112,7 +111,7 @@ export default class JitsiStreamBackgroundEffect {
//
this._outputCanvasCtx.globalCompositeOperation = 'destination-over';
if (this._options.virtualBackground.isVirtualBackground) {
if (this._options.virtualBackground.backgroundType === 'image') {
this._outputCanvasCtx.drawImage(
this._virtualImage,
0,
@ -121,7 +120,7 @@ export default class JitsiStreamBackgroundEffect {
this._inputVideoElement.height
);
} else {
this._outputCanvasCtx.filter = `blur(${blurValue})`;
this._outputCanvasCtx.filter = `blur(${this._options.virtualBackground.blurValue}px)`;
this._outputCanvasCtx.drawImage(this._inputVideoElement, 0, 0);
}
}

View File

@ -6,7 +6,7 @@
*
* @returns {{
* type: BACKGROUND_ENABLED,
* backgroundEffectEnabled: boolean,
* backgroundEffectEnabled: boolean
* }}
*/
export const BACKGROUND_ENABLED = 'BACKGROUND_ENABLED';
@ -16,8 +16,8 @@ export const BACKGROUND_ENABLED = 'BACKGROUND_ENABLED';
*
* @returns {{
* type: SET_VIRTUAL_BACKGROUND,
* isVirtualBackground: boolean,
* virtualSource: string,
* blurValue: number,
* }}
*/
export const SET_VIRTUAL_BACKGROUND = 'SET_VIRTUAL_BACKGROUND';

View File

@ -9,20 +9,20 @@ import logger from './logger';
/**
* Signals the local participant activate the virtual background video or not.
*
* @param {boolean} enabled - If true enables video background, false otherwise.
* @param {Object} options - Represents the virtual background setted options.
* @returns {Promise}
*/
export function toggleBackgroundEffect(enabled: boolean) {
export function toggleBackgroundEffect(options: Object) {
return async function(dispatch: Object => Object, getState: () => any) {
await dispatch(backgroundEnabled(options.enabled));
await dispatch(setVirtualBackground(options));
const state = getState();
const { jitsiTrack } = getLocalVideoTrack(state['features/base/tracks']);
const virtualBackground = state['features/virtual-background'];
try {
if (enabled) {
if (options.enabled) {
await jitsiTrack.setEffect(await createVirtualBackgroundEffect(virtualBackground));
dispatch(backgroundEnabled(true));
} else {
await jitsiTrack.setEffect(undefined);
dispatch(backgroundEnabled(false));
@ -37,19 +37,20 @@ export function toggleBackgroundEffect(enabled: boolean) {
/**
* Sets the selected virtual background image object.
*
* @param {Object} virtualSource - Virtual background image source.
* @param {boolean} isVirtualBackground - Indicate if virtual image is activated.
* @param {Object} options - Represents the virtual background setted options.
* @returns {{
* type: SET_VIRTUAL_BACKGROUND,
* virtualSource: string,
* isVirtualBackground: boolean,
* blurValue: number,
* type: string,
* }}
*/
export function setVirtualBackground(virtualSource: string, isVirtualBackground: boolean) {
export function setVirtualBackground(options: Object) {
return {
type: SET_VIRTUAL_BACKGROUND,
virtualSource,
isVirtualBackground
virtualSource: options?.url,
blurValue: options?.blurValue,
backgroundType: options?.backgroundType
};
}
@ -59,7 +60,7 @@ export function setVirtualBackground(virtualSource: string, isVirtualBackground:
* @param {boolean} backgroundEffectEnabled - Indicate if virtual background effect is activated.
* @returns {{
* type: BACKGROUND_ENABLED,
* backgroundEffectEnabled: boolean,
* backgroundEffectEnabled: boolean
* }}
*/
export function backgroundEnabled(backgroundEffectEnabled: boolean) {

View File

@ -10,14 +10,14 @@ import { translate } from '../../base/i18n';
import { Icon, IconBlurBackground, IconCancelSelection } from '../../base/icons';
import { connect } from '../../base/redux';
import { Tooltip } from '../../base/tooltip';
import { toggleBackgroundEffect, setVirtualBackground } from '../actions';
import { toggleBackgroundEffect } from '../actions';
import { resizeImage, toDataURL } from '../functions';
import logger from '../logger';
// The limit of virtual background uploads is 21. When the number
// of uploads is 22 we trigger the deleteStoredImage function to delete
// The limit of virtual background uploads is 24. When the number
// of uploads is 25 we trigger the deleteStoredImage function to delete
// the first/oldest uploaded background.
const backgroundsLimit = 22;
const backgroundsLimit = 25;
const images = [
{
id: 1,
@ -67,42 +67,67 @@ function VirtualBackground({ dispatch, t }: Props) {
* Updates stored images on local storage.
*/
useEffect(() => {
jitsiLocalStorage.setItem('virtualBackgrounds', JSON.stringify(storedImages));
try {
jitsiLocalStorage.setItem('virtualBackgrounds', JSON.stringify(storedImages));
} catch (err) {
// Preventing localStorage QUOTA_EXCEEDED_ERR
err && deleteStoredImage(storedImages[0]);
}
if (storedImages.length === backgroundsLimit) {
deleteStoredImage(storedImages[0]);
}
}, [ storedImages ]);
const [ selected, setSelected ] = useState('');
const enableBlur = async () => {
const enableBlur = async (blurValue, selection) => {
isloading(true);
setSelected('blur');
await dispatch(setVirtualBackground('', false));
await dispatch(toggleBackgroundEffect(true));
setSelected(selection);
await dispatch(
toggleBackgroundEffect({
backgroundType: 'blur',
enabled: true,
blurValue
})
);
isloading(false);
};
const removeBackground = async () => {
isloading(true);
setSelected('none');
await dispatch(setVirtualBackground('', false));
await dispatch(toggleBackgroundEffect(false));
await dispatch(
toggleBackgroundEffect({
enabled: false
})
);
isloading(false);
};
const setUploadedImageBackground = async image => {
isloading(true);
setSelected(image.id);
await dispatch(setVirtualBackground(image.src, true));
await dispatch(toggleBackgroundEffect(true));
await dispatch(
toggleBackgroundEffect({
backgroundType: 'image',
enabled: true,
url: image.src
})
);
isloading(false);
};
const setImageBackground = async image => {
isloading(true);
setSelected(image.id);
await dispatch(setVirtualBackground(await toDataURL(image.src), true));
await dispatch(toggleBackgroundEffect(true));
const url = await toDataURL(image.src);
await dispatch(
toggleBackgroundEffect({
backgroundType: 'image',
enabled: true,
url
})
);
isloading(false);
};
@ -111,19 +136,23 @@ function VirtualBackground({ dispatch, t }: Props) {
reader.readAsDataURL(imageFile[0]);
reader.onload = async () => {
const resizedImage = await resizeImage(reader.result);
const url = await resizeImage(reader.result);
isloading(true);
setStoredImages([
...storedImages,
{
id: uuid.v4(),
src: resizedImage
src: url
}
]);
await dispatch(setVirtualBackground(resizedImage, true));
await dispatch(toggleBackgroundEffect(true));
await dispatch(
toggleBackgroundEffect({
backgroundType: 'image',
enabled: true,
url
})
);
isloading(false);
};
reader.onerror = () => {
@ -137,7 +166,7 @@ function VirtualBackground({ dispatch, t }: Props) {
hideCancelButton = { true }
submitDisabled = { false }
titleKey = { 'virtualBackground.title' }
width = 'small'>
width = '450px'>
{loading ? (
<div className = 'virtual-background-loading'>
<span className = 'loading-content-text'>{t('virtualBackground.pleaseWait')}</span>
@ -158,11 +187,20 @@ function VirtualBackground({ dispatch, t }: Props) {
</div>
</Tooltip>
<Tooltip
content = { t('virtualBackground.enableBlur') }
content = { t('virtualBackground.slightBlur') }
position = { 'top' }>
<Icon
className = { selected === 'slight-blur' ? 'blur-selected' : '' }
onClick = { () => enableBlur(8, 'slight-blur') }
size = { 50 }
src = { IconBlurBackground } />
</Tooltip>
<Tooltip
content = { t('virtualBackground.blur') }
position = { 'top' }>
<Icon
className = { selected === 'blur' ? 'blur-selected' : '' }
onClick = { () => enableBlur() }
onClick = { () => enableBlur(25, 'blur') }
size = { 50 }
src = { IconBlurBackground } />
</Tooltip>

View File

@ -23,14 +23,15 @@ PersistenceRegistry.register(STORE_NAME, true);
* specified action.
*/
ReducerRegistry.register(STORE_NAME, (state = {}, action) => {
const { virtualSource, isVirtualBackground, backgroundEffectEnabled } = action;
const { virtualSource, backgroundEffectEnabled, blurValue, backgroundType } = action;
switch (action.type) {
case SET_VIRTUAL_BACKGROUND: {
return {
...state,
virtualSource,
isVirtualBackground
blurValue,
backgroundType
};
}
case BACKGROUND_ENABLED: {