@pexip/media-processor 20.3.5 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +109 -0
- package/README.md +17 -10
- package/api-docs/README.mdx +69 -23
- package/api-docs/functions/assertMediaStreamVideoTrack.mdx +13 -0
- package/api-docs/functions/createBenchmark.mdx +17 -5
- package/api-docs/functions/createFrameCallbackRequest.mdx +8 -2
- package/api-docs/functions/createMediaStreamTrackInputProcessAdaptor.mdx +10 -0
- package/api-docs/functions/createReadWritableStreamFallbackInputProcessAdaptor.mdx +17 -0
- package/api-docs/functions/createReadWritableStreamInputProcessAdaptor.mdx +10 -0
- package/api-docs/functions/createVideoProcessor.mdx +3 -3
- package/api-docs/functions/createWindowedStats.mdx +23 -0
- package/api-docs/functions/getDefaultInputProcessAdaptor.mdx +17 -0
- package/api-docs/functions/iou.mdx +19 -0
- package/api-docs/functions/isMediaStreamVideoTrack.mdx +13 -0
- package/api-docs/functions/labelComponents.mdx +20 -0
- package/api-docs/functions/nearestPowerOfTwo.mdx +21 -0
- package/api-docs/functions/playVideo.mdx +16 -0
- package/api-docs/functions/scoreComponent.mdx +22 -0
- package/api-docs/functions/setVideoElementSrc.mdx +14 -0
- package/api-docs/interfaces/Analyzer.mdx +4 -0
- package/api-docs/interfaces/Benchmark.mdx +26 -2
- package/api-docs/interfaces/FrameTransformStats.mdx +9 -0
- package/api-docs/interfaces/Gain.mdx +4 -0
- package/api-docs/interfaces/ImageSegmenterOptions.mdx +0 -2
- package/api-docs/interfaces/InputProcessAdaptor.mdx +28 -0
- package/api-docs/interfaces/Process.mdx +8 -3
- package/api-docs/interfaces/ProcessEventMute.mdx +6 -0
- package/api-docs/interfaces/ProcessWorkerEventOpened.mdx +7 -0
- package/api-docs/interfaces/ProcessWorkerEventStats.mdx +6 -0
- package/api-docs/interfaces/ProcessWorkerEventUpdated.mdx +7 -0
- package/api-docs/interfaces/ProcessorEvent.mdx +1 -1
- package/api-docs/interfaces/ProcessorOptions.mdx +0 -1
- package/api-docs/interfaces/ProcessorProcessOptions.mdx +3 -1
- package/api-docs/interfaces/ProcessorUpdateOptions.mdx +15 -0
- package/api-docs/interfaces/ReadWritableStream.mdx +12 -0
- package/api-docs/interfaces/Renderer.mdx +2 -2
- package/api-docs/interfaces/RendererOptions.mdx +25 -12
- package/api-docs/interfaces/Segmenter.mdx +89 -10
- package/api-docs/interfaces/SegmenterOptions.mdx +0 -1
- package/api-docs/interfaces/SelectionOptions.mdx +15 -0
- package/api-docs/interfaces/Stats.mdx +11 -0
- package/api-docs/interfaces/VideoProcessor.mdx +49 -5
- package/api-docs/interfaces/Weights.mdx +12 -0
- package/api-docs/type-aliases/OptionalKeys.mdx +10 -0
- package/api-docs/type-aliases/ProcessEvents.mdx +1 -0
- package/api-docs/type-aliases/ProcessInputType.mdx +3 -1
- package/api-docs/type-aliases/ProcessWorkerEvents.mdx +6 -4
- package/api-docs/type-aliases/ProcessorWorkerEvents.mdx +1 -1
- package/api-docs/type-aliases/Struct.mdx +9 -0
- package/api-docs/variables/BACKGROUND_THRESHOLD.mdx +3 -0
- package/api-docs/variables/DOWN_SAMPLE_FACTOR.mdx +3 -0
- package/api-docs/variables/EDGE_BLUR_AMOUNT.mdx +1 -1
- package/api-docs/variables/EXCLUDE_BYSTANDERS.mdx +3 -0
- package/api-docs/variables/FOREGROUND_THRESHOLD.mdx +1 -1
- package/api-docs/variables/FRAME_RATE.mdx +1 -1
- package/api-docs/variables/ImageFetchError.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_BLUR_AMOUNT.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_EDGE_BAND.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_INTENSITY.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_TIGHTNESS.mdx +3 -0
- package/api-docs/variables/MASK_COMBINE_RATIO.mdx +1 -1
- package/api-docs/variables/MORPH_DILATE_RADIUS_PX.mdx +3 -0
- package/api-docs/variables/MORPH_ERODE_RADIUS_PX.mdx +3 -0
- package/api-docs/variables/MORPH_PASS.mdx +3 -0
- package/api-docs/variables/MediaStreamTrackTransferable.mdx +5 -0
- package/api-docs/variables/PERSON_CENTER.mdx +3 -0
- package/api-docs/variables/RENDERER_OPTIONS_STRUCT.mdx +3 -0
- package/api-docs/variables/SIGMA_RANGE.mdx +3 -0
- package/api-docs/variables/SIGMA_SPACE.mdx +3 -0
- package/api-docs/variables/STRONG_EDGE_BLUR_AMOUNT.mdx +3 -0
- package/api-docs/variables/cloneImageRecord.mdx +19 -0
- package/api-docs/variables/compareImageRecords.mdx +18 -0
- package/api-docs/variables/createRemoteImageBitmap.mdx +1 -1
- package/api-docs/variables/getCanvasRenderingContext2D.mdx +14 -0
- package/api-docs/variables/getImageSize.mdx +13 -0
- package/api-docs/variables/isRenderOptionsKey.mdx +13 -0
- package/api-docs/variables/isValidGpuAPI.mdx +13 -0
- package/dist/common/backends/webgl/binaryMask.d.ts +8 -0
- package/dist/common/backends/webgl/binaryMask.js +95 -0
- package/dist/common/backends/webgl/blender.d.ts +2 -1
- package/dist/common/backends/webgl/blender.js +18 -15
- package/dist/common/backends/webgl/blur.d.ts +1 -1
- package/dist/common/backends/webgl/blur.js +23 -16
- package/dist/common/backends/webgl/canvas.js +9 -4
- package/dist/common/backends/webgl/diffAbsMask.d.ts +10 -0
- package/dist/common/backends/webgl/diffAbsMask.js +103 -0
- package/dist/common/backends/webgl/geodesicReconstruction.d.ts +13 -0
- package/dist/common/backends/webgl/geodesicReconstruction.js +176 -0
- package/dist/common/backends/webgl/jointBilateralFilter.d.ts +12 -0
- package/dist/common/backends/webgl/jointBilateralFilter.js +108 -0
- package/dist/common/backends/webgl/morphErode.d.ts +13 -0
- package/dist/common/backends/webgl/morphErode.js +121 -0
- package/dist/common/backends/webgl/renderer.js +194 -44
- package/dist/common/backends/webgl/replace.d.ts +17 -0
- package/dist/common/backends/webgl/replace.js +126 -0
- package/dist/common/backends/webgl/selectComponent.d.ts +15 -0
- package/dist/common/backends/webgl/selectComponent.js +102 -0
- package/dist/common/backends/webgl/smoothingMask.d.ts +3 -3
- package/dist/common/backends/webgl/smoothingMask.js +22 -21
- package/dist/common/backends/webgl/tentBlur.d.ts +9 -0
- package/dist/common/backends/webgl/tentBlur.js +118 -0
- package/dist/common/backends/webgl/texture.d.ts +2 -3
- package/dist/common/backends/webgl/texture.js +21 -19
- package/dist/common/backends/webgl/textureToTexture.d.ts +1 -1
- package/dist/common/backends/webgl/textureToTexture.js +19 -16
- package/dist/common/backends/webgl/webglUtils.d.ts +7 -1
- package/dist/common/backends/webgl/webglUtils.js +72 -10
- package/dist/common/backends/webgpu/blender.d.ts +6 -1
- package/dist/common/backends/webgpu/blender.js +96 -51
- package/dist/common/backends/webgpu/constants.js +1 -1
- package/dist/common/backends/webgpu/dualFilterBlur.d.ts +2 -3
- package/dist/common/backends/webgpu/dualFilterBlur.js +146 -140
- package/dist/common/backends/webgpu/jointBilateralFilter.d.ts +7 -0
- package/dist/common/backends/webgpu/jointBilateralFilter.js +162 -0
- package/dist/common/backends/webgpu/renderer.js +205 -43
- package/dist/common/backends/webgpu/replace.d.ts +11 -0
- package/dist/common/backends/webgpu/replace.js +175 -0
- package/dist/common/backends/webgpu/resize.d.ts +4 -0
- package/dist/common/backends/webgpu/resize.js +76 -0
- package/dist/common/backends/webgpu/smoothingMask.d.ts +2 -2
- package/dist/common/backends/webgpu/smoothingMask.js +74 -40
- package/dist/common/backends/webgpu/tentBlur.d.ts +5 -0
- package/dist/common/backends/webgpu/tentBlur.js +131 -0
- package/dist/common/backends/webgpu/texture.d.ts +2 -3
- package/dist/common/backends/webgpu/texture.js +29 -20
- package/dist/common/backends/webgpu/textureToTexture.d.ts +1 -1
- package/dist/common/backends/webgpu/textureToTexture.js +28 -15
- package/dist/common/backends/webgpu/types.d.ts +2 -0
- package/dist/common/backends/webgpu/webgpuUtils.d.ts +24 -4
- package/dist/common/backends/webgpu/webgpuUtils.js +60 -11
- package/dist/common/constants.d.ts +22 -5
- package/dist/common/constants.js +23 -5
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.js +2 -0
- package/dist/common/tsconfig.tsbuildinfo +1 -1
- package/dist/common/typeGuards.d.ts +2 -0
- package/dist/common/typeGuards.js +7 -0
- package/dist/common/types/media.d.ts +5 -1
- package/dist/common/types/messageEvents.d.ts +31 -4
- package/dist/common/types/processor.d.ts +6 -4
- package/dist/common/types/render.d.ts +147 -15
- package/dist/common/types/render.js +23 -1
- package/dist/common/types/segmentation.d.ts +0 -12
- package/dist/common/types/utils.d.ts +21 -0
- package/dist/common/utils.d.ts +29 -2
- package/dist/common/utils.js +206 -10
- package/dist/main/audio.js +3 -3
- package/dist/main/benchUtils.d.ts +35 -3
- package/dist/main/benchUtils.js +149 -15
- package/dist/main/index.d.ts +1 -1
- package/dist/main/index.js +1 -1
- package/dist/main/tsconfig.tsbuildinfo +1 -1
- package/dist/main/types.d.ts +0 -6
- package/dist/main/utils.d.ts +4 -0
- package/dist/main/utils.js +31 -0
- package/dist/main/video/constants.d.ts +1 -4
- package/dist/main/video/constants.js +1 -5
- package/dist/main/video/index.d.ts +3 -4
- package/dist/main/video/index.js +3 -4
- package/dist/main/video/inputProcessAdaptor.d.ts +30 -0
- package/dist/main/video/inputProcessAdaptor.js +198 -0
- package/dist/main/video/segmenter.d.ts +35 -0
- package/dist/main/video/{segmenters/mediapipe.js → segmenter.js} +93 -53
- package/dist/main/video/typeGuards.d.ts +2 -0
- package/dist/main/video/typeGuards.js +8 -1
- package/dist/main/video/types.d.ts +36 -16
- package/dist/main/video/utils.d.ts +5 -4
- package/dist/main/video/utils.js +49 -44
- package/dist/main/video/video.d.ts +29 -7
- package/dist/main/video/video.js +323 -28
- package/dist/workers/mediaWorker.js +35 -162
- package/dist/workers/tsconfig.tsbuildinfo +1 -1
- package/dist/worklets/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -12
- package/api-docs/functions/createCanvasTransform.mdx +0 -14
- package/api-docs/functions/createVideoTrackProcessor.mdx +0 -9
- package/api-docs/functions/createVideoTrackProcessorWithFallback.mdx +0 -15
- package/api-docs/interfaces/Detector.mdx +0 -81
- package/api-docs/interfaces/SegmentationParams.mdx +0 -18
- package/api-docs/interfaces/Transform.mdx +0 -62
- package/api-docs/type-aliases/ProcessVideoTrack.mdx +0 -15
- package/api-docs/type-aliases/SegmentationTransform.mdx +0 -3
- package/dist/common/backends/webgl/shaders/blendFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/blendFragmentShader.js +0 -21
- package/dist/common/backends/webgl/shaders/dualFilterBlurFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/dualFilterBlurFragmentShader.js +0 -45
- package/dist/common/backends/webgl/shaders/smoothingMaskFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/smoothingMaskFragmentShader.js +0 -57
- package/dist/common/backends/webgl/shaders/textureFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/textureFragmentShader.js +0 -16
- package/dist/common/backends/webgl/shaders/vertexShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/vertexShader.js +0 -19
- package/dist/main/transformer.d.ts +0 -1
- package/dist/main/transformer.js +0 -4
- package/dist/main/video/canvasTransform.d.ts +0 -17
- package/dist/main/video/canvasTransform.js +0 -253
- package/dist/main/video/segmenters/mediapipe.d.ts +0 -22
- package/dist/main/video/transformer.d.ts +0 -9
- package/dist/main/video/transformer.js +0 -68
- package/dist/main/video/videoStreamTrackProcessor.d.ts +0 -20
- package/dist/main/video/videoStreamTrackProcessor.js +0 -86
package/dist/common/utils.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import type { SegmentationModel } from './types/segmentation';
|
|
2
|
-
import type { ImageMapIterable } from './types/media';
|
|
2
|
+
import type { ImageMapIterable, ImageRecord } from './types/media';
|
|
3
3
|
import type { RenderingEvents } from './constants';
|
|
4
4
|
import type { RenderEventHandlers } from './types/render';
|
|
5
|
+
import type { Stats, SelectionOptions } from './types/utils';
|
|
5
6
|
export declare const isSegmentationModel: (t: unknown) => t is SegmentationModel;
|
|
6
7
|
export declare const isRenderingEvents: (t: unknown) => t is RenderingEvents;
|
|
7
8
|
export declare const toRenderingEvents: (t: unknown) => RenderingEvents;
|
|
8
9
|
export declare const getErrorMessage: (error: unknown) => string;
|
|
9
10
|
export declare const createObjectUpdater: <T extends { [K in keyof T]: unknown; }>(original: T) => (another: Partial<T>) => void;
|
|
11
|
+
export declare const ImageFetchError = "ImageFetchError";
|
|
10
12
|
export declare const createRemoteImageBitmap: (map?: ImageMapIterable) => {
|
|
11
|
-
tryFetchingImage: (uri: string) => Promise<ImageBitmap | null>;
|
|
13
|
+
tryFetchingImage: (uri: string, abortSignal: AbortSignal) => Promise<ImageBitmap | null | undefined>;
|
|
12
14
|
setImage: (uri: string, image: ImageBitmap) => void;
|
|
13
15
|
getImage: (uri: string) => ImageBitmap | null;
|
|
14
16
|
removeImage: (uri: string) => boolean;
|
|
@@ -16,6 +18,12 @@ export declare const createRemoteImageBitmap: (map?: ImageMapIterable) => {
|
|
|
16
18
|
};
|
|
17
19
|
export declare const clamping: (min: number, max: number) => (value: number) => number;
|
|
18
20
|
export declare const calculateMaxBlurPass: (height: number) => number;
|
|
21
|
+
/**
|
|
22
|
+
* Coerce any positive number to the nearest power of two within [minPow, maxPow]
|
|
23
|
+
* Example: nearestPowerOfTwo(13) => 16; nearestPowerOfTwo(3.2) => 4
|
|
24
|
+
*/
|
|
25
|
+
export declare function nearestPowerOfTwo(n: number, minPow?: number, // 2^0 = 1
|
|
26
|
+
maxPow?: number): number;
|
|
19
27
|
/**
|
|
20
28
|
* Calculate the coordinates and size of the source and destination to fit the
|
|
21
29
|
* target aspect ratio.
|
|
@@ -37,3 +45,22 @@ export declare const resize: (fromWidth: number, fromHeight: number, toWidth: nu
|
|
|
37
45
|
};
|
|
38
46
|
export declare const createLazyProps: <T extends Record<string, unknown>>(stateBuilder: { [K in keyof T]: (s: Partial<T>) => T[K]; }) => T;
|
|
39
47
|
export declare const handleWebGLContextLoss: (canvas: OffscreenCanvas, eventHandlers: RenderEventHandlers, contextLostCb?: () => void) => () => void;
|
|
48
|
+
/**
|
|
49
|
+
* Intersection over Union (IoU), how much two masks overlap as a fraction of either's total.
|
|
50
|
+
* 1.0 = perfect match, 0 = no overlap.
|
|
51
|
+
* Used for stable, robust tracking of the main person between frames,
|
|
52
|
+
* especially with bystander removal and temporal instance switching.
|
|
53
|
+
*/
|
|
54
|
+
export declare function iou(a: Uint8Array, b: Uint8Array): number;
|
|
55
|
+
export declare function labelComponents(input: Uint8Array, labels: Int32Array, width: number, height: number): Map<number, Stats>;
|
|
56
|
+
export declare function scoreComponent(stats: Stats, overlap: number, weights: SelectionOptions, width: number, height: number): number;
|
|
57
|
+
export declare const cloneImageRecord: (image: ImageRecord) => Promise<{
|
|
58
|
+
image: ImageBitmap;
|
|
59
|
+
key: string;
|
|
60
|
+
}>;
|
|
61
|
+
/**
|
|
62
|
+
* Compare provided ImageRecord
|
|
63
|
+
*
|
|
64
|
+
* @returns true if the two records have the same key and image, false otherwise
|
|
65
|
+
*/
|
|
66
|
+
export declare const compareImageRecords: (a: ImageRecord, b: ImageRecord | undefined) => boolean;
|
package/dist/common/utils.js
CHANGED
|
@@ -31,26 +31,52 @@ export const createObjectUpdater = (original) => {
|
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
|
+
export const ImageFetchError = 'ImageFetchError';
|
|
35
|
+
const isLikelyImageContentType = (ct) => {
|
|
36
|
+
if (!ct) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
// handle e.g. "image/png; charset=binary"
|
|
40
|
+
return ct.toLowerCase().startsWith('image/');
|
|
41
|
+
};
|
|
34
42
|
export const createRemoteImageBitmap = (map) => {
|
|
35
43
|
const cache = new Map(map);
|
|
36
44
|
const fetchingCache = new Set();
|
|
37
|
-
const fetchImage = async (uri) => {
|
|
38
|
-
const response = await fetch(uri);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
const fetchImage = async (uri, abortSignal) => {
|
|
46
|
+
const response = await fetch(uri, { signal: abortSignal });
|
|
47
|
+
if (response.ok &&
|
|
48
|
+
isLikelyImageContentType(response.headers.get('content-type'))) {
|
|
49
|
+
const blob = await response.blob();
|
|
50
|
+
const image = await createImageBitmap(blob);
|
|
51
|
+
return image;
|
|
52
|
+
}
|
|
42
53
|
};
|
|
43
|
-
const tryFetchingImage = async (uri) => {
|
|
54
|
+
const tryFetchingImage = async (uri, abortSignal) => {
|
|
44
55
|
const image = cache.get(uri);
|
|
45
56
|
if (!image) {
|
|
46
57
|
if (fetchingCache.has(uri)) {
|
|
47
58
|
return null;
|
|
48
59
|
}
|
|
49
60
|
fetchingCache.add(uri);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
try {
|
|
62
|
+
const image = await fetchImage(uri, abortSignal);
|
|
63
|
+
if (image) {
|
|
64
|
+
cache.set(uri, image);
|
|
65
|
+
return image;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error instanceof Error) {
|
|
70
|
+
if (error.name !== 'AbortError') {
|
|
71
|
+
throw new Error(ImageFetchError, { cause: error });
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
fetchingCache.delete(uri);
|
|
79
|
+
}
|
|
54
80
|
}
|
|
55
81
|
return image;
|
|
56
82
|
};
|
|
@@ -81,6 +107,18 @@ export const createRemoteImageBitmap = (map) => {
|
|
|
81
107
|
};
|
|
82
108
|
export const clamping = (min, max) => (value) => Math.min(Math.max(value, min), max);
|
|
83
109
|
export const calculateMaxBlurPass = (height) => Math.trunc(Math.log2(height));
|
|
110
|
+
/**
|
|
111
|
+
* Coerce any positive number to the nearest power of two within [minPow, maxPow]
|
|
112
|
+
* Example: nearestPowerOfTwo(13) => 16; nearestPowerOfTwo(3.2) => 4
|
|
113
|
+
*/
|
|
114
|
+
export function nearestPowerOfTwo(n, minPow = 0, // 2^0 = 1
|
|
115
|
+
maxPow = 4) {
|
|
116
|
+
if (n <= 0) {
|
|
117
|
+
return 1;
|
|
118
|
+
}
|
|
119
|
+
const k = clamping(minPow, maxPow)(calculateMaxBlurPass(n));
|
|
120
|
+
return 2 ** k;
|
|
121
|
+
}
|
|
84
122
|
/**
|
|
85
123
|
* Calculate the coordinates and size of the source and destination to fit the
|
|
86
124
|
* target aspect ratio.
|
|
@@ -171,3 +209,161 @@ export const handleWebGLContextLoss = (canvas, eventHandlers, contextLostCb) =>
|
|
|
171
209
|
canvas.removeEventListener('webglcontextcreationerror', handleContextCreationError);
|
|
172
210
|
};
|
|
173
211
|
};
|
|
212
|
+
/**
|
|
213
|
+
* Intersection over Union (IoU), how much two masks overlap as a fraction of either's total.
|
|
214
|
+
* 1.0 = perfect match, 0 = no overlap.
|
|
215
|
+
* Used for stable, robust tracking of the main person between frames,
|
|
216
|
+
* especially with bystander removal and temporal instance switching.
|
|
217
|
+
*/
|
|
218
|
+
export function iou(a, b) {
|
|
219
|
+
let inter = 0;
|
|
220
|
+
let union = 0;
|
|
221
|
+
for (let i = 0; i < a.length; i++) {
|
|
222
|
+
// @ts-expect-error TypeArray will not be undefined
|
|
223
|
+
const av = a[i] >= 128;
|
|
224
|
+
// @ts-expect-error TypeArray will not be undefined
|
|
225
|
+
const bv = b[i] >= 128;
|
|
226
|
+
if (av && bv) {
|
|
227
|
+
inter++;
|
|
228
|
+
}
|
|
229
|
+
if (av || bv) {
|
|
230
|
+
union++;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return union ? inter / union : 0;
|
|
234
|
+
}
|
|
235
|
+
export function labelComponents(input, labels, width, height) {
|
|
236
|
+
// 8-connected component labeling with union-find
|
|
237
|
+
let nextLabel = 1;
|
|
238
|
+
const parent = [0];
|
|
239
|
+
function find(x) {
|
|
240
|
+
if (parent[x] === undefined) {
|
|
241
|
+
return x;
|
|
242
|
+
}
|
|
243
|
+
if (parent[x] !== x) {
|
|
244
|
+
parent[x] = find(parent[x]);
|
|
245
|
+
}
|
|
246
|
+
return parent[x];
|
|
247
|
+
}
|
|
248
|
+
function unite(a, b) {
|
|
249
|
+
if (!a || !b) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
a = find(a);
|
|
253
|
+
b = find(b);
|
|
254
|
+
if (a !== b) {
|
|
255
|
+
parent[b] = a; // Or vice versa, as long as consistent
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// First pass: assign and union with neighbors (left, top, top-left, top-right)
|
|
259
|
+
for (let y = 0; y < height; y++) {
|
|
260
|
+
for (let x = 0; x < width; x++) {
|
|
261
|
+
const i = y * width + x;
|
|
262
|
+
//@ts-expect-error will not be undefined
|
|
263
|
+
if (input[i] < 128) {
|
|
264
|
+
labels[i] = 0;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const left = x > 0 ? labels[i - 1] : 0;
|
|
268
|
+
const top = y > 0 ? labels[i - width] : 0;
|
|
269
|
+
const topLeft = x > 0 && y > 0 ? labels[i - width - 1] : 0;
|
|
270
|
+
const topRight = x < width - 1 && y > 0 ? labels[i - width + 1] : 0;
|
|
271
|
+
// Pick an existing neighbor label if present, else new
|
|
272
|
+
let assign = left || top || topLeft || topRight;
|
|
273
|
+
if (!assign) {
|
|
274
|
+
assign = nextLabel++;
|
|
275
|
+
parent[assign] = assign;
|
|
276
|
+
}
|
|
277
|
+
labels[i] = assign;
|
|
278
|
+
// Union all differing neighbors with the assigned label
|
|
279
|
+
if (left && left !== assign) {
|
|
280
|
+
unite(assign, left);
|
|
281
|
+
}
|
|
282
|
+
if (top && top !== assign) {
|
|
283
|
+
unite(assign, top);
|
|
284
|
+
}
|
|
285
|
+
if (topLeft && topLeft !== assign) {
|
|
286
|
+
unite(assign, topLeft);
|
|
287
|
+
}
|
|
288
|
+
if (topRight && topRight !== assign) {
|
|
289
|
+
unite(assign, topRight);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// Second pass: compress labels to root ids
|
|
294
|
+
for (let i = 0; i < labels.length; i++) {
|
|
295
|
+
const l = labels[i];
|
|
296
|
+
labels[i] = l ? find(l) : 0;
|
|
297
|
+
}
|
|
298
|
+
// Compute component stats for selection
|
|
299
|
+
const stats = new Map();
|
|
300
|
+
for (let y = 0; y < height; y++) {
|
|
301
|
+
for (let x = 0; x < width; x++) {
|
|
302
|
+
const l = labels[y * width + x];
|
|
303
|
+
if (!l) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const s = stats.get(l) ?? {
|
|
307
|
+
sumX: 0,
|
|
308
|
+
sumY: 0,
|
|
309
|
+
count: 0,
|
|
310
|
+
minX: width,
|
|
311
|
+
minY: height,
|
|
312
|
+
maxX: -1,
|
|
313
|
+
maxY: -1,
|
|
314
|
+
};
|
|
315
|
+
s.sumX += x;
|
|
316
|
+
s.sumY += y;
|
|
317
|
+
s.count++;
|
|
318
|
+
if (x < s.minX) {
|
|
319
|
+
s.minX = x;
|
|
320
|
+
}
|
|
321
|
+
if (x > s.maxX) {
|
|
322
|
+
s.maxX = x;
|
|
323
|
+
}
|
|
324
|
+
if (y < s.minY) {
|
|
325
|
+
s.minY = y;
|
|
326
|
+
}
|
|
327
|
+
if (y > s.maxY) {
|
|
328
|
+
s.maxY = y;
|
|
329
|
+
}
|
|
330
|
+
stats.set(l, s);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return stats;
|
|
334
|
+
}
|
|
335
|
+
export function scoreComponent(stats, overlap, weights, width, height) {
|
|
336
|
+
const area = stats.count;
|
|
337
|
+
const heightPx = stats.maxY - stats.minY + 1;
|
|
338
|
+
// const widthPx = stats.maxX - stats.minX + 1;
|
|
339
|
+
const mx = stats.sumX / stats.count;
|
|
340
|
+
const my = stats.sumY / stats.count;
|
|
341
|
+
const d2 = (mx - weights.centerX) ** 2 + (my - weights.centerY) ** 2;
|
|
342
|
+
const centerScore = 1.0 - Math.min(1.0, Math.sqrt(d2) / Math.max(width, height)); // normalize
|
|
343
|
+
// Normalize area/height by frame size to [0..1]
|
|
344
|
+
const areaN = area / (width * height);
|
|
345
|
+
const heightN = heightPx / height;
|
|
346
|
+
const score = weights.iou * overlap +
|
|
347
|
+
weights.area * areaN +
|
|
348
|
+
weights.height * heightN +
|
|
349
|
+
weights.center * centerScore;
|
|
350
|
+
return score;
|
|
351
|
+
}
|
|
352
|
+
export const cloneImageRecord = async (image) => {
|
|
353
|
+
const cloned = await createImageBitmap(image.image);
|
|
354
|
+
return { image: cloned, key: image.key };
|
|
355
|
+
};
|
|
356
|
+
/**
|
|
357
|
+
* Compare provided ImageRecord
|
|
358
|
+
*
|
|
359
|
+
* @returns true if the two records have the same key and image, false otherwise
|
|
360
|
+
*/
|
|
361
|
+
export const compareImageRecords = (a, b) => {
|
|
362
|
+
if (!b) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
if (a.key !== b.key || a.image !== b.image) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
return true;
|
|
369
|
+
};
|
package/dist/main/audio.js
CHANGED
|
@@ -341,8 +341,8 @@ function createBaseAudioNode(name, create, release) {
|
|
|
341
341
|
* @param shouldResetEnabled - Whether or not to enable the cloned track
|
|
342
342
|
*/
|
|
343
343
|
export const createStreamSourceGraphNode = (mediaStream, shouldResetEnabled = true) => {
|
|
344
|
-
let stream
|
|
345
|
-
let unsubscribeUnmutes
|
|
344
|
+
let stream;
|
|
345
|
+
let unsubscribeUnmutes;
|
|
346
346
|
return createBaseAudioNode('source', context => {
|
|
347
347
|
stream = createMediaStreamAudioClone(mediaStream);
|
|
348
348
|
// Enabled the track for the cloned stream
|
|
@@ -448,7 +448,7 @@ export const createAnalyzerGraphNode = (options) => {
|
|
|
448
448
|
* Create a MediaStreamAudioDestinationNodeInit
|
|
449
449
|
*/
|
|
450
450
|
export const createStreamDestinationGraphNode = (options) => {
|
|
451
|
-
let node
|
|
451
|
+
let node;
|
|
452
452
|
return createBaseAudioNode('destination', context => {
|
|
453
453
|
node = createMediaStreamAudioDestinationNode(context, options);
|
|
454
454
|
return [node, node];
|
|
@@ -2,12 +2,44 @@ import type { Clock } from './types';
|
|
|
2
2
|
type FPS = number;
|
|
3
3
|
type Timestamp = number;
|
|
4
4
|
export interface Benchmark {
|
|
5
|
-
begin(): void;
|
|
6
|
-
end(): void;
|
|
5
|
+
begin(timestamp?: number): void;
|
|
6
|
+
end(timestamp?: number): void;
|
|
7
|
+
reset(): void;
|
|
7
8
|
calculateFps(): [Timestamp, FPS];
|
|
8
9
|
}
|
|
9
10
|
interface BenchmarkOptions {
|
|
10
11
|
calculationThresholdMS?: number;
|
|
12
|
+
warmupCount?: number;
|
|
13
|
+
averageThreshold?: number;
|
|
14
|
+
bufferSize?: number;
|
|
11
15
|
}
|
|
12
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Creates a benchmarking utility for measuring frame durations and calculating frames per second (FPS).
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* This function is designed for performance measurement in animation or game loops.
|
|
21
|
+
* It records frame start/end times, ignores an initial warmup period, utilizes a circular buffer
|
|
22
|
+
* to average recent frame durations, and computes a smoothed FPS value on demand.
|
|
23
|
+
* The calculation may only occur if sufficient samples have been gathered and the minimum interval between
|
|
24
|
+
* calculations has elapsed.
|
|
25
|
+
*
|
|
26
|
+
* @param clock - An object with a `now()` method returning the current timestamp (in milliseconds). Defaults to `window.performance`.
|
|
27
|
+
* @param options - Optional configuration options for the benchmark utility.
|
|
28
|
+
* @param options.bufferSize - Size of the circular buffer used to store recent frame durations. Defaults to 1024.
|
|
29
|
+
* @param options.calculationThresholdMS - Minimum interval in milliseconds between FPS recalculations. Defaults to 1000.
|
|
30
|
+
* @param options.warmupCount - Number of initial frames to ignore before starting to record durations. Defaults to 100.
|
|
31
|
+
* @param options.averageThreshold - Minimum number of samples in the buffer required before calculating FPS. Defaults to 100.
|
|
32
|
+
*
|
|
33
|
+
* @returns An object with methods to start/end frame measurements, reset the benchmark, and calculate current FPS.
|
|
34
|
+
*/
|
|
35
|
+
export declare const createBenchmark: (clock?: Clock, { bufferSize, calculationThresholdMS, warmupCount, averageThreshold, }?: BenchmarkOptions) => Benchmark;
|
|
36
|
+
export declare const createWindowedStats: (windowSize?: number) => {
|
|
37
|
+
add(value: number): void;
|
|
38
|
+
readonly mean: number;
|
|
39
|
+
readonly variance: number;
|
|
40
|
+
readonly stddev: number;
|
|
41
|
+
readonly stdError: number;
|
|
42
|
+
readonly count: number;
|
|
43
|
+
clear(): void;
|
|
44
|
+
};
|
|
13
45
|
export {};
|
package/dist/main/benchUtils.js
CHANGED
|
@@ -1,35 +1,169 @@
|
|
|
1
|
-
|
|
1
|
+
import { createCircularBuffer } from '@pexip/utils';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a benchmarking utility for measuring frame durations and calculating frames per second (FPS).
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* This function is designed for performance measurement in animation or game loops.
|
|
7
|
+
* It records frame start/end times, ignores an initial warmup period, utilizes a circular buffer
|
|
8
|
+
* to average recent frame durations, and computes a smoothed FPS value on demand.
|
|
9
|
+
* The calculation may only occur if sufficient samples have been gathered and the minimum interval between
|
|
10
|
+
* calculations has elapsed.
|
|
11
|
+
*
|
|
12
|
+
* @param clock - An object with a `now()` method returning the current timestamp (in milliseconds). Defaults to `window.performance`.
|
|
13
|
+
* @param options - Optional configuration options for the benchmark utility.
|
|
14
|
+
* @param options.bufferSize - Size of the circular buffer used to store recent frame durations. Defaults to 1024.
|
|
15
|
+
* @param options.calculationThresholdMS - Minimum interval in milliseconds between FPS recalculations. Defaults to 1000.
|
|
16
|
+
* @param options.warmupCount - Number of initial frames to ignore before starting to record durations. Defaults to 100.
|
|
17
|
+
* @param options.averageThreshold - Minimum number of samples in the buffer required before calculating FPS. Defaults to 100.
|
|
18
|
+
*
|
|
19
|
+
* @returns An object with methods to start/end frame measurements, reset the benchmark, and calculate current FPS.
|
|
20
|
+
*/
|
|
21
|
+
export const createBenchmark = (clock = performance, { bufferSize = 2 ** 10, calculationThresholdMS = 1000, warmupCount = 100, averageThreshold = 100, } = {}) => {
|
|
2
22
|
const props = {
|
|
23
|
+
buffer: createCircularBuffer(bufferSize, Float32Array),
|
|
3
24
|
beginTime: 0,
|
|
4
25
|
endTime: 0,
|
|
5
|
-
sumDelta: 0,
|
|
6
|
-
count: 0,
|
|
7
26
|
lastCalculateTime: 0,
|
|
8
27
|
lastResult: 0,
|
|
28
|
+
warmupCount: 0,
|
|
29
|
+
sum: 0,
|
|
9
30
|
};
|
|
10
31
|
return {
|
|
11
|
-
begin: () => {
|
|
12
|
-
props.
|
|
32
|
+
begin: (timestamp = clock.now()) => {
|
|
33
|
+
if (props.warmupCount < warmupCount) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
props.beginTime = timestamp;
|
|
37
|
+
},
|
|
38
|
+
end: (timestamp = clock.now()) => {
|
|
39
|
+
if (props.warmupCount < warmupCount) {
|
|
40
|
+
props.warmupCount += 1;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
props.endTime = timestamp;
|
|
44
|
+
if (props.buffer.isFull()) {
|
|
45
|
+
const oldest = props.buffer.peek() ?? 0;
|
|
46
|
+
props.sum -= oldest;
|
|
47
|
+
}
|
|
48
|
+
const elapsed = props.endTime - props.beginTime;
|
|
49
|
+
props.buffer.push(elapsed);
|
|
50
|
+
props.sum += elapsed;
|
|
13
51
|
},
|
|
14
|
-
|
|
15
|
-
props.
|
|
16
|
-
props.
|
|
17
|
-
|
|
52
|
+
reset: () => {
|
|
53
|
+
props.buffer.clear();
|
|
54
|
+
props.warmupCount = 0;
|
|
55
|
+
props.beginTime = 0;
|
|
56
|
+
props.endTime = 0;
|
|
57
|
+
props.lastCalculateTime = 0;
|
|
18
58
|
},
|
|
19
59
|
calculateFps: () => {
|
|
60
|
+
if (props.warmupCount < warmupCount) {
|
|
61
|
+
return [props.lastCalculateTime, props.lastResult];
|
|
62
|
+
}
|
|
20
63
|
const calculateTime = clock.now();
|
|
21
64
|
const lastDuration = calculateTime - props.lastCalculateTime;
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
props.sumDelta = 0;
|
|
27
|
-
props.count = 0;
|
|
65
|
+
if (props.lastCalculateTime &&
|
|
66
|
+
lastDuration >= calculationThresholdMS &&
|
|
67
|
+
props.buffer.size() > averageThreshold) {
|
|
68
|
+
const result = (lastDuration * props.buffer.size()) / props.sum;
|
|
28
69
|
props.lastCalculateTime = calculateTime;
|
|
29
70
|
props.lastResult = result;
|
|
30
71
|
return [calculateTime, result];
|
|
31
72
|
}
|
|
73
|
+
props.lastCalculateTime = calculateTime;
|
|
32
74
|
return [props.lastCalculateTime, props.lastResult];
|
|
33
75
|
},
|
|
34
76
|
};
|
|
35
77
|
};
|
|
78
|
+
function mean(sum, count) {
|
|
79
|
+
if (count > 0) {
|
|
80
|
+
return sum / count;
|
|
81
|
+
}
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
function variance(count, mean, sumSquare) {
|
|
85
|
+
if (count < 2) {
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
return sumSquare / count - mean * mean;
|
|
89
|
+
}
|
|
90
|
+
function stddev(variance) {
|
|
91
|
+
return Math.sqrt(variance);
|
|
92
|
+
}
|
|
93
|
+
function stdError(count, stddev) {
|
|
94
|
+
if (count === 0) {
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
return stddev / Math.sqrt(count);
|
|
98
|
+
}
|
|
99
|
+
export const createWindowedStats = (windowSize = 2 ** 10) => {
|
|
100
|
+
const props = {
|
|
101
|
+
buffer: createCircularBuffer(windowSize, Float32Array),
|
|
102
|
+
sum: 0,
|
|
103
|
+
sumSqr: 0,
|
|
104
|
+
};
|
|
105
|
+
const cache = {
|
|
106
|
+
mean: 0,
|
|
107
|
+
variance: 0,
|
|
108
|
+
stddev: 0,
|
|
109
|
+
stdError: 0,
|
|
110
|
+
};
|
|
111
|
+
const dirty = {
|
|
112
|
+
mean: false,
|
|
113
|
+
variance: false,
|
|
114
|
+
stddev: false,
|
|
115
|
+
stdError: false,
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
add(value) {
|
|
119
|
+
if (props.buffer.isFull()) {
|
|
120
|
+
const oldest = props.buffer.peek() ?? 0;
|
|
121
|
+
props.sum -= oldest;
|
|
122
|
+
props.sumSqr -= oldest * oldest;
|
|
123
|
+
}
|
|
124
|
+
props.buffer.push(value);
|
|
125
|
+
props.sum += value;
|
|
126
|
+
props.sumSqr += value * value;
|
|
127
|
+
dirty.mean = true;
|
|
128
|
+
dirty.variance = true;
|
|
129
|
+
dirty.stddev = true;
|
|
130
|
+
dirty.stdError = true;
|
|
131
|
+
},
|
|
132
|
+
get mean() {
|
|
133
|
+
if (dirty.mean) {
|
|
134
|
+
cache.mean = mean(props.sum, this.count);
|
|
135
|
+
dirty.mean = false;
|
|
136
|
+
}
|
|
137
|
+
return cache.mean;
|
|
138
|
+
},
|
|
139
|
+
get variance() {
|
|
140
|
+
if (dirty.variance) {
|
|
141
|
+
cache.variance = variance(this.count, this.mean, props.sumSqr);
|
|
142
|
+
dirty.variance = false;
|
|
143
|
+
}
|
|
144
|
+
return cache.variance;
|
|
145
|
+
},
|
|
146
|
+
get stddev() {
|
|
147
|
+
if (dirty.stddev) {
|
|
148
|
+
cache.stddev = stddev(this.variance);
|
|
149
|
+
dirty.stddev = false;
|
|
150
|
+
}
|
|
151
|
+
return cache.stddev;
|
|
152
|
+
},
|
|
153
|
+
get stdError() {
|
|
154
|
+
if (dirty.stdError) {
|
|
155
|
+
cache.stdError = stdError(this.count, this.stddev);
|
|
156
|
+
dirty.stdError = false;
|
|
157
|
+
}
|
|
158
|
+
return cache.stdError;
|
|
159
|
+
},
|
|
160
|
+
get count() {
|
|
161
|
+
return props.buffer.size();
|
|
162
|
+
},
|
|
163
|
+
clear() {
|
|
164
|
+
props.buffer.clear();
|
|
165
|
+
props.sum = 0;
|
|
166
|
+
props.sumSqr = 0;
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
};
|
package/dist/main/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export * from './types';
|
|
|
10
10
|
export * from './math';
|
|
11
11
|
export * from './process';
|
|
12
12
|
export * from './typeGuards';
|
|
13
|
-
export { createAsyncCallbackLoop } from './utils';
|
|
13
|
+
export { createAsyncCallbackLoop, MediaStreamTrackTransferable } from './utils';
|
|
14
14
|
export * from './benchUtils';
|
|
15
15
|
export declare const urls: {
|
|
16
16
|
denoise: () => URL;
|
package/dist/main/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export * from './types';
|
|
|
10
10
|
export * from './math';
|
|
11
11
|
export * from './process';
|
|
12
12
|
export * from './typeGuards';
|
|
13
|
-
export { createAsyncCallbackLoop } from './utils';
|
|
13
|
+
export { createAsyncCallbackLoop, MediaStreamTrackTransferable } from './utils';
|
|
14
14
|
export * from './benchUtils';
|
|
15
15
|
export const urls = {
|
|
16
16
|
denoise: () => new URL('../worklets/denoise.worklet.js', import.meta.url),
|