in src/backgroundfilter/BackgroundFilterProcessor.ts [296:394]
async process(buffers: VideoFrameBuffer[]): Promise<VideoFrameBuffer[]> {
if (this.destroyed) {
return buffers;
}
this.frameCounter.frameReceived(buffers[0].framerate);
this.cpuMonitor.frameReceived();
const inputCanvas = buffers[0].asCanvasElement() as HTMLCanvasElement;
if (!inputCanvas) {
return buffers;
}
if (!this.modelInitialized) {
// return existing buffer, if any
buffers[0] = this.canvasVideoFrameBuffer;
return buffers;
}
const frameWidth = inputCanvas.width;
const frameHeight = inputCanvas.height;
if (frameWidth === 0 || frameHeight === 0) {
return buffers;
}
// on first execution of process the source width will be zero
if (this.sourceWidth === 0) {
this.sourceWidth = frameWidth;
this.sourceHeight = frameHeight;
// update target canvas size to match the frame size
this.targetCanvas.width = this.sourceWidth;
this.targetCanvas.height = this.sourceHeight;
this.logger.info(`${this.filterType} source width: ${this.sourceWidth}`);
this.logger.info(`${this.filterType} source height: ${this.sourceHeight}`);
this.initOnFirstExecution();
}
if (this.sourceWidth !== frameWidth || this.sourceHeight !== frameHeight) {
this.sourceWidth = frameWidth;
this.sourceHeight = frameHeight;
// update target canvas size to match the frame size
this.targetCanvas.width = this.sourceWidth;
this.targetCanvas.height = this.sourceHeight;
}
try {
this.frameCounter.filterSubmitted();
let mask = this.mask$.value;
const hscale = this.spec.model.input.width / inputCanvas.width;
const vscale = this.spec.model.input.height / inputCanvas.height;
if (this.scaledCanvas === undefined) {
this.scaledCanvas = document.createElement('canvas');
this.scaledCanvas.width = this.spec.model.input.width;
this.scaledCanvas.height = this.spec.model.input.height;
}
const scaledCtx = this.scaledCanvas.getContext('2d');
scaledCtx.save();
scaledCtx.scale(hscale, vscale);
scaledCtx.drawImage(inputCanvas, 0, 0);
scaledCtx.restore();
const imageData = scaledCtx.getImageData(
0,
0,
this.scaledCanvas.width,
this.scaledCanvas.height
);
// update the filter mask based on the filter update rate
if (this.frameNumber % this.videoFramesPerFilterUpdate === 0) {
// process frame...
const maskPromise = this.mask$.whenNext();
this.worker.postMessage({ msg: 'predict', payload: imageData }, [imageData.data.buffer]);
mask = await maskPromise;
}
// It's possible that while waiting for the predict to complete the processor was destroyed.
// adding a destroyed check here to ensure the implementation of drawImageWithMask does not throw
// an error due to destroyed processor.
if (!this.destroyed) {
this.drawImageWithMask(inputCanvas, mask);
}
} catch (error) {
this.logger.error(`could not process ${this.filterType} frame buffer due to ${error}`);
return buffers;
} finally {
this.frameCounter.filterComplete();
this.frameNumber++;
}
buffers[0] = this.canvasVideoFrameBuffer;
return buffers;
}