Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VideoProcessors v3 (Preview 1) #80

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c157012
Hybrid pipeline POC: Only the person mask upscale stage is based on a…
manjeshbhargav Jul 4, 2024
8e836c6
Hybrid pipeline POC: Working around lack of Canvas2D blur filter feat…
manjeshbhargav Jul 5, 2024
5056970
Some refactoring.
manjeshbhargav Jul 6, 2024
c7617ec
Refactor to implement a 2-pass bilateral filter.
manjeshbhargav Jul 11, 2024
a8bd626
Add logarithmic stepping to bilateral filter and pre-calculate color …
manjeshbhargav Jul 25, 2024
fed0dea
Refactor gaussian blur fragment shader.
manjeshbhargav Jul 26, 2024
fff49be
* Support bitmaprenderer output frame buffer context.
manjeshbhargav Jul 28, 2024
2756056
Refactoring the processing code into a separate BackgroundProcessorPi…
manjeshbhargav Jul 29, 2024
2bc2467
Implementing configurable web workers for the background processing p…
manjeshbhargav Jul 30, 2024
d04276c
Some refactoring.
manjeshbhargav Jul 30, 2024
0e7de0e
* Fixing assets path for web workers.
manjeshbhargav Jul 31, 2024
fd65db7
* Some refactoring and adding the option to defer input frame downscale.
manjeshbhargav Jul 31, 2024
74c0f22
* Removing pipeline from stats.
manjeshbhargav Aug 1, 2024
56f4bba
* Merging web worker benchmark with the one on the main thread.
manjeshbhargav Aug 1, 2024
2398655
* Passing current unit/integration tests.
manjeshbhargav Aug 9, 2024
99708f7
Resetting WebGL2 pipelines when output canvas dimensions change.
manjeshbhargav Aug 9, 2024
655f32b
CHANGELOG.md entry for 3.0.0-preview.1.
manjeshbhargav Aug 12, 2024
79c7eac
3.0.0-preview.1
twilio-ci Aug 13, 2024
e3c41f4
3.0.0-dev
twilio-ci Aug 13, 2024
c8640b3
VBLOCKS-3490 Supporting CORS web workers (#83)
manjeshbhargav Sep 16, 2024
69ba3f4
3.0.0-preview.2
twilio-ci Sep 16, 2024
76a038a
3.0.0-dev
twilio-ci Sep 16, 2024
f551ea5
VBLOCKS-3643 VBLOCKS-3644 Support web workers on Safari and Firefox (…
manjeshbhargav Oct 22, 2024
9794f72
Merge branch 'master' into video-processors-v3
manjeshbhargav Oct 22, 2024
d1ab129
3.0.0-rc.1
twilio-ci Oct 22, 2024
d510b90
3.0.0-dev
twilio-ci Oct 22, 2024
a41209b
Prep for 3.0.0-beta.1 (#88)
manjeshbhargav Dec 4, 2024
53f6f1f
3.0.0-beta.1
twilio-ci Dec 4, 2024
3545ad1
3.0.0-dev
twilio-ci Dec 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
3.0.0-beta.1 (December 4, 2024)
===============================

* Web workers are now supported for Firefox and Safari.

3.0.0-preview.2 (September 16, 2024)
====================================

* The web workers can now be hosted on a different domain than that of the application, provided the `Access-Control-Allow-Origin` response header points to the domain of the application.
```ts
import { GaussianBlurBackgroundProcessor } from '@twilio/video-processors';

/* Application is running at https://appserver.com/app */

const processor = new GaussianBlurBackgroundProcessor({
assetsPath: "https://assetsserver.com/path/to/assets"
});
```

3.0.0-preview.1 (August 13, 2024)
=================================

*The 3.x version of the Video Processors SDK works with `twilio-video` SDK versions `2.29.0` and above.*

API Changes
-----------

* The VideoProcessors now run in web workers on Chromium-based browsers. Support for web workers on other supported browsers is upcoming. While adding a `VideoProcessor` to a `VideoTrack`, use the following `AddProcessorOptions`:
```ts
videoTrack.addProcessor(processor, {
inputFrameBufferType: 'videoframe',
outputFrameBufferContextType: 'bitmaprenderer'
});
```
* The `Canvas2D` and `WebGL2` pipelines are replaced by a single hybrid pipeline. Therefore, the following APIs are no longer available:
* `BackgroundProcessorOptions.pipeline`
* `Pipeline` enum exported by `@twilio/video-processors`

Performance Improvements
------------------------

*TODO(mmalavalli)*

2.2.0 (July 16, 2024)
=====================

Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
The following license applies to all parts of this software except as
documented below.

Copyright (C) 2022 Twilio Inc.
Copyright (C) 2025 Twilio Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ You can also copy `twilio-video-processors.js` from the `dist/build` folder and

### Assets

In order to achieve the best performance, the VideoProcessors use WebAssembly to run TensorFlow Lite for person segmentation. You need to serve the tflite model and binaries so they can be loaded properly. These files can be downloaded from the `dist/build` folder. Check the [API docs](https://twilio.github.io/twilio-video-processors.js/interfaces/VirtualBackgroundProcessorOptions.html#assetsPath) for details and the [examples](https://github.com/twilio/twilio-video-processors.js/tree/master/examples) folder for reference.
In order to achieve the best performance, the VideoProcessors use WebAssembly to run TensorFlow Lite for person segmentation. You need to serve the tflite model, binaries and web workers so they can be loaded properly. These files can be downloaded from the `dist/build` folder. Check the [API docs](https://twilio.github.io/twilio-video-processors.js/interfaces/VirtualBackgroundProcessorOptions.html#assetsPath) for details and the [examples](https://github.com/twilio/twilio-video-processors.js/tree/master/examples) folder for reference.

#### CORS

If you are serving the assets from a domain that is different from that of your application, then ensure that the `Access-Control-Allow-Origin` response header points to your application's domain.

## Usage

Expand Down
Binary file modified assets/selfie_segmentation_landscape.tflite
Binary file not shown.
20 changes: 20 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const globals = require("globals");
const pluginJs = require("@eslint/js");
const tseslint = require("typescript-eslint");


module.exports = [
{ files: ["lib/**/*.ts"] },
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
{
rules: {
"@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-namespace": "warn",
"no-unused-vars": "warn",
"no-undef": "warn",
},
},
];
7 changes: 4 additions & 3 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ Go to `${PROJECT_ROOT}/examples` and run `npm install`. It will install the depe

Open `http://localhost:3000` in a Chrome tab. The app captures your camera upon loading and plays it in a `<video>` element. You can choose to enable, disable or update the background settings using the controls on the page. Additionally, you can specify the following url parameters:

- `blurFilterRadius` - Radius of the background blur filter (default: 15)
- `capFramerate` - Choose video capture frame rate (default: 30)
- `capResolution=wxh` - Choose video capture resolution (default: 1280x720)
- `debounce=true|false` - Whether to skip processing every other frame (default: false)
- `maskBlurRadius` - Radius of the mask blur filter (default: 8 for WebGL2, 4 for Canvas2D)
- `pipeline=Canvas2D|WebGL2` - Choose the canvas or webgl pipeline (default: WebGL2)
- `deferInputFrameDownscale=true|false` - **(Chrome only)** Whether to calculate the person mask without waiting for the input frame to be downscaled (default: false)
- `maskBlurRadius` - Radius of the mask blur filter (default: 8)
- `stats=advanced|hide|show` - Show performance benchmarks (default: show)
- `useWebWorker=true|false` - **(Chrome only)** Whether to use a web worker for background replacement (default: true)
2 changes: 1 addition & 1 deletion examples/virtualbackground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ <h5 class="modal-title" id="errorModalLabel">Error</h5>
</div>
</div>
</div>
<script src="https://sdk.twilio.com/js/video/releases/2.28.1/twilio-video.js"></script>
<script src="twilio-video.js"></script>
<script src="twilio-video-processors.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous"></script>
<script type="module" src="https://cdn.jsdelivr.net/gh/zerodevx/zero-md@2/dist/zero-md.min.js"></script>
Expand Down
38 changes: 17 additions & 21 deletions examples/virtualbackground/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ const assetsPath = '';
const bkgImages = new Map();

const defaultParams = {
blurFilterRadius: '15',
capFramerate: '30',
capResolution: '1280x720',
debounce: 'false',
pipeline: 'WebGL2',
maskBlurRadiusCanvas2D: '4',
maskBlurRadiusWebGL2: '8',
deferInputFrameDownscale: 'false',
maskBlurRadius: '8',
stats: 'show',
useWebWorker: 'true',
};

const params = {
Expand Down Expand Up @@ -45,35 +46,28 @@ const loadImage = async (name) => {
return bkgImage;
}

params.maskBlurRadius = params.pipeline === 'WebGL2'
? params.maskBlurRadiusWebGL2
: params.maskBlurRadiusCanvas2D;

(async ({
Video: { createLocalVideoTrack },
VideoProcessors: {
GaussianBlurBackgroundProcessor,
Pipeline: { Canvas2D, WebGL2 },
VirtualBackgroundProcessor,
isSupported,
version,
},
}) => {
const {
blurFilterRadius,
capFramerate,
capResolution,
pipeline,
debounce,
deferInputFrameDownscale,
maskBlurRadius,
stats = 'show',
stats,
useWebWorker,
} = params;

const addProcessorOptions = {
inputFrameBufferType: 'video',
outputFrameBufferContextType: {
[Canvas2D]: '2d',
[WebGL2]: 'webgl2',
}[pipeline],
inputFrameBufferType: 'videoframe',
outputFrameBufferContextType: 'bitmaprenderer',
};

const capDimensions = capResolution
Expand All @@ -88,9 +82,9 @@ params.maskBlurRadius = params.pipeline === 'WebGL2'

const processorOptions = {
assetsPath,
pipeline,
debounce: JSON.parse(debounce),
deferInputFrameDownscale: JSON.parse(deferInputFrameDownscale),
maskBlurRadius: Number(maskBlurRadius),
useWebWorker: JSON.parse(useWebWorker),
};

let videoTrack = null;
Expand Down Expand Up @@ -129,7 +123,10 @@ params.maskBlurRadius = params.pipeline === 'WebGL2'
setProcessor(videoTrack, null);
} else if (bg === 'blur') {
if (!gaussianBlurProcessor) {
gaussianBlurProcessor = new GaussianBlurBackgroundProcessor(processorOptions);
gaussianBlurProcessor = new GaussianBlurBackgroundProcessor({
blurFilterRadius: Number(blurFilterRadius),
...processorOptions,
});
await gaussianBlurProcessor.loadModel();
}
setProcessor(videoTrack, gaussianBlurProcessor);
Expand Down Expand Up @@ -158,7 +155,6 @@ params.maskBlurRadius = params.pipeline === 'WebGL2'
}
const { frameRate, height, width } = videoTrack.mediaStreamTrack.getSettings();
$stats.innerText = `Sdk version: ${version}`;
$stats.innerText += `\nPipeline: ${params.pipeline}`;
$stats.innerText += `\nCapture dimensions (in): ${width} x ${height}`;
$stats.innerText += `\nFrame rate (in): ${frameRate.toFixed(2)} fps`;

Expand Down
3 changes: 1 addition & 2 deletions karma.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ export default function(config: any) {
karmaTypescriptConfig: {
coverageOptions: {
exclude: [
/tests\/.*/,
/lib\/processors\/webgl2\/.*/
/tests\/.*/
]
},
include: [
Expand Down
4 changes: 3 additions & 1 deletion lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ export const MASK_BLUR_RADIUS = 8;
export const MODEL_NAME = 'selfie_segmentation_landscape.tflite';
export const TFLITE_LOADER_NAME = 'tflite-1-0-0.js';
export const TFLITE_SIMD_LOADER_NAME = 'tflite-simd-1-0-0.js';
export const TFLITE_WORKER_NAME = 'tflite-worker.js';
export const TWILIO_GAUSSIAN_BLUR_BACKGROUND_PROCESSOR_PIPELINE_WORKER = 'twilio-gaussian-blur-background-processor-pipeline-worker.js';
export const TWILIO_VIRTUAL_BACKGROUND_PROCESSOR_PIPELINE_WORKER = 'twilio-virtual-background-processor-pipeline-worker.js';


export const WASM_INFERENCE_DIMENSIONS: Dimensions = {
width: 256,
Expand Down
4 changes: 1 addition & 3 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GaussianBlurBackgroundProcessor, GaussianBlurBackgroundProcessorOptions } from './processors/background/GaussianBlurBackgroundProcessor';
import { VirtualBackgroundProcessor, VirtualBackgroundProcessorOptions } from './processors/background/VirtualBackgroundProcessor';
import { ImageFit, Pipeline } from './types';
import { ImageFit } from './types';
import { isSupported } from './utils/support';
import { version } from './utils/version';

Expand All @@ -10,7 +10,6 @@ if (typeof window !== 'undefined') {
...window.Twilio.VideoProcessors,
GaussianBlurBackgroundProcessor,
ImageFit,
Pipeline,
isSupported,
version,
VirtualBackgroundProcessor,
Expand All @@ -21,7 +20,6 @@ export {
GaussianBlurBackgroundProcessor,
GaussianBlurBackgroundProcessorOptions,
ImageFit,
Pipeline,
isSupported,
version,
VirtualBackgroundProcessor,
Expand Down
2 changes: 1 addition & 1 deletion lib/processors/Processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ export abstract class Processor {
* @param outputFrameBuffer - The output frame buffer to use to draw the processed frame.
*/
abstract processFrame(
inputFrameBuffer: OffscreenCanvas | HTMLCanvasElement | HTMLVideoElement,
inputFrameBuffer: OffscreenCanvas | HTMLCanvasElement | HTMLVideoElement | VideoFrame,
outputFrameBuffer: HTMLCanvasElement): Promise<void> | void;
}
Loading