@webex/ladon-ts 5.9.0 → 5.9.1
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 +7 -0
- package/build/module/lib/pipeline.d.ts +6 -0
- package/build/module/lib/pipeline.js +58 -50
- package/build/module/lib/pipeline.js.map +1 -1
- package/build/module/lib/version.d.ts +1 -1
- package/build/module/lib/version.js +1 -1
- package/build/module/lib/version.js.map +1 -1
- package/build/worker/segmentation.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### 5.9.1 (2025-07-02)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **pipeline:** resolve mask lag regression and clarify frame data paths ([#77](https://github.com/beyonddunbar/ladon-ts/issues/77)) ([5e7a3a8](https://github.com/beyonddunbar/ladon-ts/commit/5e7a3a840f8d478ee7d62bb19275653ffe152766))
|
|
11
|
+
|
|
5
12
|
## 5.9.0 (2025-07-01)
|
|
6
13
|
|
|
7
14
|
|
|
@@ -24,6 +24,8 @@ export declare class Pipeline implements IPipeline {
|
|
|
24
24
|
private isProcessingFrame;
|
|
25
25
|
/** Promise for the currently pending frame processing operation. */
|
|
26
26
|
private pendingFramePromise;
|
|
27
|
+
/** Buffer for frame data copies to ensure they are not modified or garbage collected. */
|
|
28
|
+
private frameDataBuffer?;
|
|
27
29
|
/**
|
|
28
30
|
* Create a new pipeline instance.
|
|
29
31
|
*
|
|
@@ -63,6 +65,10 @@ export declare class Pipeline implements IPipeline {
|
|
|
63
65
|
* @returns The frame data as a Uint8ClampedArray.
|
|
64
66
|
*/
|
|
65
67
|
private getInputFrameData;
|
|
68
|
+
/**
|
|
69
|
+
* Create a copy of frame data to prevent modifications during async operations.
|
|
70
|
+
*/
|
|
71
|
+
private createFrameDataCopy;
|
|
66
72
|
/**
|
|
67
73
|
* Resize the image data if the model expects a different input size.
|
|
68
74
|
* Handles scaling between input dimensions and model requirements.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { WorkerGenerator as
|
|
2
|
-
import { BlurRenderer as
|
|
3
|
-
import { PassthroughRenderer as
|
|
1
|
+
import { WorkerGenerator as f } from "./worker-generator.js";
|
|
2
|
+
import { BlurRenderer as w } from "./renderer/blur-renderer.js";
|
|
3
|
+
import { PassthroughRenderer as F } from "./renderer/passthrough-renderer.js";
|
|
4
4
|
import { ReplacementRenderer as k } from "./renderer/replacement-renderer.js";
|
|
5
|
-
import { resizeImage as
|
|
6
|
-
class
|
|
5
|
+
import { resizeImage as y } from "./util.js";
|
|
6
|
+
class A {
|
|
7
7
|
/**
|
|
8
8
|
* Create a new pipeline instance.
|
|
9
9
|
*
|
|
@@ -13,15 +13,15 @@ class M {
|
|
|
13
13
|
* @param inputVideoElement - Video element serving as the input source.
|
|
14
14
|
* @throws Error if the input canvas 2D context cannot be obtained.
|
|
15
15
|
*/
|
|
16
|
-
constructor(
|
|
17
|
-
this.inputCanvas =
|
|
18
|
-
const
|
|
16
|
+
constructor(e, t, r, n) {
|
|
17
|
+
this.inputCanvas = e, this.outputCanvas = t, this.config = r, this.inputVideoElement = n, this.loaded = !1, this.isProcessingFrame = !1, this.pendingFramePromise = null;
|
|
18
|
+
const s = this.inputCanvas.getContext("2d", {
|
|
19
19
|
alpha: !1,
|
|
20
20
|
willReadFrequently: !0
|
|
21
21
|
});
|
|
22
|
-
if (!
|
|
22
|
+
if (!s)
|
|
23
23
|
throw new Error("[ladon-ts] Error getting input context 2d");
|
|
24
|
-
this.inputCanvasContext =
|
|
24
|
+
this.inputCanvasContext = s;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Process a single frame and return the inference result.
|
|
@@ -34,13 +34,13 @@ class M {
|
|
|
34
34
|
* @returns Promise resolving to the frame processing result with timing statistics.
|
|
35
35
|
* @throws Error if the pipeline (generator or renderer) is not loaded.
|
|
36
36
|
*/
|
|
37
|
-
async onFrame(
|
|
37
|
+
async onFrame(e, t = !0, r) {
|
|
38
38
|
this.isProcessingFrame && this.pendingFramePromise && await this.pendingFramePromise, this.isProcessingFrame = !0;
|
|
39
39
|
try {
|
|
40
40
|
return this.pendingFramePromise = this.processFrameInternal(
|
|
41
|
-
t,
|
|
42
41
|
e,
|
|
43
|
-
|
|
42
|
+
t,
|
|
43
|
+
r
|
|
44
44
|
), await this.pendingFramePromise;
|
|
45
45
|
} finally {
|
|
46
46
|
this.isProcessingFrame = !1, this.pendingFramePromise = null;
|
|
@@ -56,29 +56,30 @@ class M {
|
|
|
56
56
|
* @returns Promise resolving to the frame processing result with timing statistics.
|
|
57
57
|
* @throws Error if the pipeline (generator or renderer) is not loaded.
|
|
58
58
|
*/
|
|
59
|
-
async processFrameInternal(
|
|
59
|
+
async processFrameInternal(e, t = !0, r) {
|
|
60
60
|
const n = performance.now();
|
|
61
61
|
if (!this.generator || !this.renderer)
|
|
62
62
|
throw new Error("[ladon-ts] Pipeline is not loaded.");
|
|
63
|
-
let
|
|
64
|
-
if (
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
await this.generator.process(
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
63
|
+
let s = 0, i = 0, a;
|
|
64
|
+
if (t || !this.lastMaskResult) {
|
|
65
|
+
const m = performance.now();
|
|
66
|
+
r ?? (r = this.getInputFrameData()), a = this.createFrameDataCopy(r), s = performance.now() - m;
|
|
67
|
+
const c = performance.now(), p = r, g = this.getMaskImageData(p);
|
|
68
|
+
await this.generator.process(g, e), this.lastMaskResult = await this.generator.getLadonOutputForTimestamp(e), i = performance.now() - c;
|
|
69
|
+
} else
|
|
70
|
+
a = this.inputVideoElement;
|
|
71
|
+
const d = performance.now();
|
|
72
|
+
await this.renderer.render(a, this.lastMaskResult);
|
|
73
|
+
const l = performance.now() - d, o = performance.now(), u = o - n, h = this.createInferenceResult(e, t);
|
|
74
|
+
return h.stats = {
|
|
75
|
+
totalFrameTime: u,
|
|
76
|
+
modelInferenceTime: i,
|
|
77
|
+
preprocessingTime: s,
|
|
78
|
+
postprocessingTime: l,
|
|
78
79
|
frameStartTime: n,
|
|
79
|
-
frameEndTime:
|
|
80
|
-
inferenceSkipped: !
|
|
81
|
-
},
|
|
80
|
+
frameEndTime: o,
|
|
81
|
+
inferenceSkipped: !t
|
|
82
|
+
}, h;
|
|
82
83
|
}
|
|
83
84
|
/**
|
|
84
85
|
* Get the raw image data from the input canvas context.
|
|
@@ -93,6 +94,13 @@ class M {
|
|
|
93
94
|
this.config.input.height
|
|
94
95
|
).data;
|
|
95
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Create a copy of frame data to prevent modifications during async operations.
|
|
99
|
+
*/
|
|
100
|
+
createFrameDataCopy(e) {
|
|
101
|
+
var t;
|
|
102
|
+
return e instanceof Uint8ClampedArray ? (((t = this.frameDataBuffer) == null ? void 0 : t.length) !== e.length && (this.frameDataBuffer = new Uint8ClampedArray(e.length)), this.frameDataBuffer.set(e), this.frameDataBuffer) : e;
|
|
103
|
+
}
|
|
96
104
|
/**
|
|
97
105
|
* Resize the image data if the model expects a different input size.
|
|
98
106
|
* Handles scaling between input dimensions and model requirements.
|
|
@@ -100,14 +108,14 @@ class M {
|
|
|
100
108
|
* @param rawImageData - The raw image data to potentially resize.
|
|
101
109
|
* @returns The processed mask image data, resized if necessary.
|
|
102
110
|
*/
|
|
103
|
-
getMaskImageData(
|
|
104
|
-
const
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
getMaskImageData(e) {
|
|
112
|
+
const t = this.config.mask.inputSize, r = this.config.input;
|
|
113
|
+
return t.width === r.width && t.height === r.height ? e : y(
|
|
114
|
+
e,
|
|
115
|
+
r.width,
|
|
116
|
+
r.height,
|
|
117
|
+
t.width,
|
|
118
|
+
t.height
|
|
111
119
|
);
|
|
112
120
|
}
|
|
113
121
|
/**
|
|
@@ -118,20 +126,20 @@ class M {
|
|
|
118
126
|
* @param performedInference - Whether inference was actually performed for this frame.
|
|
119
127
|
* @returns The inference result object containing mask data and metadata.
|
|
120
128
|
*/
|
|
121
|
-
createInferenceResult(
|
|
129
|
+
createInferenceResult(e, t) {
|
|
122
130
|
return this.lastMaskResult ? {
|
|
123
131
|
facesAndLandmarks: this.lastMaskResult.facesAndLandmarks,
|
|
124
132
|
gesture: this.lastMaskResult.gesture,
|
|
125
133
|
motion: this.lastMaskResult.motion,
|
|
126
|
-
skipped: !
|
|
127
|
-
timestamp:
|
|
134
|
+
skipped: !t,
|
|
135
|
+
timestamp: e
|
|
128
136
|
// Stats will be added by the caller if needed
|
|
129
137
|
} : {
|
|
130
138
|
facesAndLandmarks: { data: new Float32Array(0), dims: [] },
|
|
131
139
|
gesture: new Float32Array(0),
|
|
132
140
|
motion: 0,
|
|
133
141
|
skipped: !0,
|
|
134
|
-
timestamp:
|
|
142
|
+
timestamp: e
|
|
135
143
|
// Stats will be added by the caller if needed
|
|
136
144
|
};
|
|
137
145
|
}
|
|
@@ -153,10 +161,10 @@ class M {
|
|
|
153
161
|
async load() {
|
|
154
162
|
switch (this.config.render.type) {
|
|
155
163
|
case "blur":
|
|
156
|
-
this.renderer = new
|
|
164
|
+
this.renderer = new w(this.outputCanvas, this.config);
|
|
157
165
|
break;
|
|
158
166
|
case "passthrough":
|
|
159
|
-
this.renderer = new
|
|
167
|
+
this.renderer = new F(this.outputCanvas, this.config);
|
|
160
168
|
break;
|
|
161
169
|
case "replacement":
|
|
162
170
|
this.renderer = new k(this.outputCanvas, this.config);
|
|
@@ -164,7 +172,7 @@ class M {
|
|
|
164
172
|
default:
|
|
165
173
|
throw new Error("[ladon-ts] Renderer not implemented.");
|
|
166
174
|
}
|
|
167
|
-
await this.renderer.load(), this.generator = new
|
|
175
|
+
await this.renderer.load(), this.generator = new f(this.config), await this.generator.load(), this.loaded = !0;
|
|
168
176
|
}
|
|
169
177
|
/**
|
|
170
178
|
* Reset the pipeline state by clearing cached mask results.
|
|
@@ -180,11 +188,11 @@ class M {
|
|
|
180
188
|
* @returns Promise that resolves when cleanup is complete.
|
|
181
189
|
*/
|
|
182
190
|
async destroy() {
|
|
183
|
-
var
|
|
184
|
-
this.reset(), (
|
|
191
|
+
var e, t;
|
|
192
|
+
this.reset(), (e = this.renderer) == null || e.destroy(), await ((t = this.generator) == null ? void 0 : t.destroy()), this.loaded = !1;
|
|
185
193
|
}
|
|
186
194
|
}
|
|
187
195
|
export {
|
|
188
|
-
|
|
196
|
+
A as Pipeline
|
|
189
197
|
};
|
|
190
198
|
//# sourceMappingURL=pipeline.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.js","sources":["../../../src/lib/pipeline.ts"],"sourcesContent":["import { PipelineConfig } from './config-types';\nimport { FrameData, LadonOutput, MaskGenerator, WorkerGenerator } from './generator';\nimport { IFrameInferenceResult, IPipeline } from './pipeline-types';\nimport { BlurRenderer, LadonRenderer, PassthroughRenderer, ReplacementRenderer } from './renderer';\nimport { resizeImage } from './util';\n\n/**\n * Core pipeline implementation for processing video frames with ML inference and rendering.\n * Handles frame processing, mask generation, and output rendering with proper timing controls.\n */\nexport class Pipeline implements IPipeline {\n /** The mask generator responsible for ML inference. */\n private generator?: MaskGenerator;\n\n /** The renderer responsible for compositing the final output. */\n private renderer?: LadonRenderer;\n\n /** Flag indicating whether the pipeline has been fully loaded and initialized. */\n private loaded = false;\n\n /** 2D rendering context for the input canvas used for frame processing. */\n private inputCanvasContext: CanvasRenderingContext2D;\n\n /** The most recent mask result from ML inference, used when skipping inference. */\n private lastMaskResult?: LadonOutput;\n\n /** Flag indicating whether a frame is currently being processed. */\n private isProcessingFrame = false;\n\n /** Promise for the currently pending frame processing operation. */\n private pendingFramePromise: Promise<IFrameInferenceResult> | null = null;\n\n /**\n * Create a new pipeline instance.\n *\n * @param inputCanvas - Canvas element for input frame processing.\n * @param outputCanvas - Canvas element where the final rendered output will be displayed.\n * @param config - Pipeline configuration containing processing and rendering settings.\n * @param inputVideoElement - Video element serving as the input source.\n * @throws Error if the input canvas 2D context cannot be obtained.\n */\n constructor(\n private inputCanvas: HTMLCanvasElement,\n private outputCanvas: HTMLCanvasElement,\n public readonly config: PipelineConfig,\n private readonly inputVideoElement: HTMLVideoElement\n ) {\n const inputCanvasContext = this.inputCanvas.getContext('2d', {\n alpha: false,\n willReadFrequently: true,\n });\n\n if (!inputCanvasContext) {\n throw new Error('[ladon-ts] Error getting input context 2d');\n }\n this.inputCanvasContext = inputCanvasContext;\n }\n\n /**\n * Process a single frame and return the inference result.\n * This method handles frame data, performs inference if needed, and renders the output.\n * Includes frame processing serialization to prevent overlapping operations.\n *\n * @param timestamp - The timestamp of the frame in milliseconds.\n * @param performInference - Whether to perform mask inference or reuse the last result.\n * @param frameData - Optional frame data to process instead of capturing from input.\n * @returns Promise resolving to the frame processing result with timing statistics.\n * @throws Error if the pipeline (generator or renderer) is not loaded.\n */\n public async onFrame(\n timestamp: number,\n performInference = true,\n frameData?: FrameData\n ): Promise<IFrameInferenceResult> {\n // If already processing, wait for the current frame to finish\n if (this.isProcessingFrame && this.pendingFramePromise) {\n await this.pendingFramePromise;\n }\n\n // Set processing flag\n this.isProcessingFrame = true;\n\n try {\n this.pendingFramePromise = this.processFrameInternal(\n timestamp,\n performInference,\n frameData\n );\n return await this.pendingFramePromise;\n } finally {\n this.isProcessingFrame = false;\n this.pendingFramePromise = null;\n }\n }\n\n /**\n * Internal frame processing implementation.\n * Handles the actual frame processing logic including timing measurements.\n *\n * @param timestamp - The timestamp of the frame in milliseconds.\n * @param performInference - Whether to perform mask inference or reuse the last result.\n * @param frameData - Optional frame data to process instead of capturing from input.\n * @returns Promise resolving to the frame processing result with timing statistics.\n * @throws Error if the pipeline (generator or renderer) is not loaded.\n */\n private async processFrameInternal(\n timestamp: number,\n performInference = true,\n frameData?: FrameData\n ): Promise<IFrameInferenceResult> {\n const frameStartTime = performance.now();\n\n if (!this.generator || !this.renderer) {\n throw new Error('[ladon-ts] Pipeline is not loaded.');\n }\n\n let preprocessingTime = 0;\n let modelInferenceTime = 0;\n\n if (performInference || !this.lastMaskResult) {\n // Pre-processing timing\n const preprocessStart = performance.now();\n\n // Get the current frame (raw image data or video element). Use the video element if skipping\n // inference to avoid unnecessary processing when calling canvas getImageData.\n frameData ??= this.getInputFrameData();\n\n preprocessingTime = performance.now() - preprocessStart;\n\n // Model inference timing\n const inferenceStart = performance.now();\n\n // Send frame for inference and wait for the mask for this timestamp\n const rawImageData = frameData as Uint8ClampedArray;\n const maskImageData = this.getMaskImageData(rawImageData);\n await this.generator.process(maskImageData, timestamp);\n this.lastMaskResult = await this.generator.getLadonOutputForTimestamp(timestamp);\n\n modelInferenceTime = performance.now() - inferenceStart;\n }\n\n // Post-processing timing (rendering)\n const postprocessStart = performance.now();\n\n // Render the frame and mask together (mask may be stale if skipping inference)\n await this.renderer.render(this.inputVideoElement, this.lastMaskResult);\n\n const postprocessingTime = performance.now() - postprocessStart;\n\n const frameEndTime = performance.now();\n const totalFrameTime = frameEndTime - frameStartTime;\n\n const result = this.createInferenceResult(timestamp, performInference);\n\n // Add timing stats to the result\n result.stats = {\n totalFrameTime,\n modelInferenceTime,\n preprocessingTime,\n postprocessingTime,\n frameStartTime,\n frameEndTime,\n inferenceSkipped: !performInference,\n };\n\n return result;\n }\n\n /**\n * Get the raw image data from the input canvas context.\n *\n * @returns The frame data as a Uint8ClampedArray.\n */\n private getInputFrameData(): FrameData {\n return this.inputCanvasContext.getImageData(\n 0,\n 0,\n this.config.input.width,\n this.config.input.height\n ).data;\n }\n\n /**\n * Resize the image data if the model expects a different input size.\n * Handles scaling between input dimensions and model requirements.\n *\n * @param rawImageData - The raw image data to potentially resize.\n * @returns The processed mask image data, resized if necessary.\n */\n private getMaskImageData(rawImageData: Uint8ClampedArray): Uint8ClampedArray {\n const modelInput = this.config.mask.inputSize;\n const inputImage = this.config.input;\n\n // Check if resizing is needed based on configuration.\n if (modelInput.width === inputImage.width && modelInput.height === inputImage.height) {\n return rawImageData;\n }\n\n // Resize the image data.\n return resizeImage(\n rawImageData,\n inputImage.width,\n inputImage.height,\n modelInput.width,\n modelInput.height\n );\n }\n\n /**\n * Create the inference result object with appropriate data.\n * Handles both successful inference results and fallback cases.\n *\n * @param timestamp - The timestamp of the frame in milliseconds.\n * @param performedInference - Whether inference was actually performed for this frame.\n * @returns The inference result object containing mask data and metadata.\n */\n private createInferenceResult(\n timestamp: number,\n performedInference: boolean\n ): IFrameInferenceResult {\n if (!this.lastMaskResult) {\n return {\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n skipped: true,\n timestamp,\n // Stats will be added by the caller if needed\n };\n }\n\n return {\n facesAndLandmarks: this.lastMaskResult.facesAndLandmarks,\n gesture: this.lastMaskResult.gesture,\n motion: this.lastMaskResult.motion,\n skipped: !performedInference,\n timestamp,\n // Stats will be added by the caller if needed\n };\n }\n\n /**\n * Check if the pipeline is fully loaded and ready for processing.\n *\n * @returns True if the pipeline is loaded and ready, false otherwise.\n */\n public isLoaded(): boolean {\n return this.loaded;\n }\n\n /**\n * Load and initialize the pipeline components.\n * Creates the appropriate renderer and generator based on configuration.\n *\n * @returns Promise that resolves when all components are loaded and ready.\n * @throws Error if an unsupported renderer type is specified in the configuration.\n */\n public async load(): Promise<void> {\n switch (this.config.render.type) {\n case 'blur':\n this.renderer = new BlurRenderer(this.outputCanvas, this.config);\n break;\n case 'passthrough':\n this.renderer = new PassthroughRenderer(this.outputCanvas, this.config);\n break;\n case 'replacement':\n this.renderer = new ReplacementRenderer(this.outputCanvas, this.config);\n break;\n default:\n throw new Error('[ladon-ts] Renderer not implemented.');\n }\n\n await this.renderer.load();\n\n this.generator = new WorkerGenerator(this.config);\n await this.generator.load();\n\n this.loaded = true;\n }\n\n /**\n * Reset the pipeline state by clearing cached mask results.\n * Useful when switching between different processing modes or sources.\n */\n public reset(): void {\n this.lastMaskResult = undefined;\n }\n\n /**\n * Destroy the pipeline and clean up all resources.\n * Properly disposes of the renderer and generator to prevent memory leaks.\n *\n * @returns Promise that resolves when cleanup is complete.\n */\n public async destroy(): Promise<void> {\n this.reset();\n this.renderer?.destroy();\n await this.generator?.destroy();\n this.loaded = false;\n }\n}\n"],"names":["Pipeline","inputCanvas","outputCanvas","config","inputVideoElement","inputCanvasContext","timestamp","performInference","frameData","frameStartTime","preprocessingTime","modelInferenceTime","preprocessStart","inferenceStart","rawImageData","maskImageData","postprocessStart","postprocessingTime","frameEndTime","totalFrameTime","result","modelInput","inputImage","resizeImage","performedInference","BlurRenderer","PassthroughRenderer","ReplacementRenderer","WorkerGenerator","_a","_b"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pipeline.js","sources":["../../../src/lib/pipeline.ts"],"sourcesContent":["import { PipelineConfig } from './config-types';\nimport { FrameData, LadonOutput, MaskGenerator, WorkerGenerator } from './generator';\nimport { IFrameInferenceResult, IPipeline } from './pipeline-types';\nimport { BlurRenderer, LadonRenderer, PassthroughRenderer, ReplacementRenderer } from './renderer';\nimport { resizeImage } from './util';\n\n/**\n * Core pipeline implementation for processing video frames with ML inference and rendering.\n * Handles frame processing, mask generation, and output rendering with proper timing controls.\n */\nexport class Pipeline implements IPipeline {\n /** The mask generator responsible for ML inference. */\n private generator?: MaskGenerator;\n\n /** The renderer responsible for compositing the final output. */\n private renderer?: LadonRenderer;\n\n /** Flag indicating whether the pipeline has been fully loaded and initialized. */\n private loaded = false;\n\n /** 2D rendering context for the input canvas used for frame processing. */\n private inputCanvasContext: CanvasRenderingContext2D;\n\n /** The most recent mask result from ML inference, used when skipping inference. */\n private lastMaskResult?: LadonOutput;\n\n /** Flag indicating whether a frame is currently being processed. */\n private isProcessingFrame = false;\n\n /** Promise for the currently pending frame processing operation. */\n private pendingFramePromise: Promise<IFrameInferenceResult> | null = null;\n\n /** Buffer for frame data copies to ensure they are not modified or garbage collected. */\n private frameDataBuffer?: Uint8ClampedArray;\n\n /**\n * Create a new pipeline instance.\n *\n * @param inputCanvas - Canvas element for input frame processing.\n * @param outputCanvas - Canvas element where the final rendered output will be displayed.\n * @param config - Pipeline configuration containing processing and rendering settings.\n * @param inputVideoElement - Video element serving as the input source.\n * @throws Error if the input canvas 2D context cannot be obtained.\n */\n constructor(\n private inputCanvas: HTMLCanvasElement,\n private outputCanvas: HTMLCanvasElement,\n public readonly config: PipelineConfig,\n private readonly inputVideoElement: HTMLVideoElement\n ) {\n const inputCanvasContext = this.inputCanvas.getContext('2d', {\n alpha: false,\n willReadFrequently: true,\n });\n\n if (!inputCanvasContext) {\n throw new Error('[ladon-ts] Error getting input context 2d');\n }\n this.inputCanvasContext = inputCanvasContext;\n }\n\n /**\n * Process a single frame and return the inference result.\n * This method handles frame data, performs inference if needed, and renders the output.\n * Includes frame processing serialization to prevent overlapping operations.\n *\n * @param timestamp - The timestamp of the frame in milliseconds.\n * @param performInference - Whether to perform mask inference or reuse the last result.\n * @param frameData - Optional frame data to process instead of capturing from input.\n * @returns Promise resolving to the frame processing result with timing statistics.\n * @throws Error if the pipeline (generator or renderer) is not loaded.\n */\n public async onFrame(\n timestamp: number,\n performInference = true,\n frameData?: FrameData\n ): Promise<IFrameInferenceResult> {\n // If already processing, wait for the current frame to finish\n if (this.isProcessingFrame && this.pendingFramePromise) {\n await this.pendingFramePromise;\n }\n\n // Set processing flag\n this.isProcessingFrame = true;\n\n try {\n this.pendingFramePromise = this.processFrameInternal(\n timestamp,\n performInference,\n frameData\n );\n return await this.pendingFramePromise;\n } finally {\n this.isProcessingFrame = false;\n this.pendingFramePromise = null;\n }\n }\n\n /**\n * Internal frame processing implementation.\n * Handles the actual frame processing logic including timing measurements.\n *\n * @param timestamp - The timestamp of the frame in milliseconds.\n * @param performInference - Whether to perform mask inference or reuse the last result.\n * @param frameData - Optional frame data to process instead of capturing from input.\n * @returns Promise resolving to the frame processing result with timing statistics.\n * @throws Error if the pipeline (generator or renderer) is not loaded.\n */\n private async processFrameInternal(\n timestamp: number,\n performInference = true,\n frameData?: FrameData\n ): Promise<IFrameInferenceResult> {\n const frameStartTime = performance.now();\n\n if (!this.generator || !this.renderer) {\n throw new Error('[ladon-ts] Pipeline is not loaded.');\n }\n\n let preprocessingTime = 0;\n let modelInferenceTime = 0;\n let renderFrameData: FrameData;\n\n if (performInference || !this.lastMaskResult) {\n // INFERENCE PATH: Capture canvas data, generate mask, render with same data\n const preprocessStart = performance.now();\n\n // Get canvas data for inference\n frameData ??= this.getInputFrameData();\n\n // Create stable copy for rendering synchronization\n renderFrameData = this.createFrameDataCopy(frameData);\n\n preprocessingTime = performance.now() - preprocessStart;\n\n // Generate mask\n const inferenceStart = performance.now();\n const rawImageData = frameData as Uint8ClampedArray;\n const maskImageData = this.getMaskImageData(rawImageData);\n await this.generator.process(maskImageData, timestamp);\n this.lastMaskResult = await this.generator.getLadonOutputForTimestamp(timestamp);\n modelInferenceTime = performance.now() - inferenceStart;\n } else {\n // SKIP INFERENCE PATH: Use video element directly for GPU optimization\n renderFrameData = this.inputVideoElement;\n }\n\n // Render with appropriate frame data\n const postprocessStart = performance.now();\n await this.renderer.render(renderFrameData, this.lastMaskResult);\n const postprocessingTime = performance.now() - postprocessStart;\n\n const frameEndTime = performance.now();\n const totalFrameTime = frameEndTime - frameStartTime;\n\n const result = this.createInferenceResult(timestamp, performInference);\n result.stats = {\n totalFrameTime,\n modelInferenceTime,\n preprocessingTime,\n postprocessingTime,\n frameStartTime,\n frameEndTime,\n inferenceSkipped: !performInference,\n };\n\n return result;\n }\n\n /**\n * Get the raw image data from the input canvas context.\n *\n * @returns The frame data as a Uint8ClampedArray.\n */\n private getInputFrameData(): FrameData {\n return this.inputCanvasContext.getImageData(\n 0,\n 0,\n this.config.input.width,\n this.config.input.height\n ).data;\n }\n\n /**\n * Create a copy of frame data to prevent modifications during async operations.\n */\n private createFrameDataCopy(frameData: FrameData): FrameData {\n if (frameData instanceof Uint8ClampedArray) {\n if (this.frameDataBuffer?.length !== frameData.length) {\n this.frameDataBuffer = new Uint8ClampedArray(frameData.length);\n }\n this.frameDataBuffer.set(frameData);\n return this.frameDataBuffer;\n }\n return frameData;\n }\n\n /**\n * Resize the image data if the model expects a different input size.\n * Handles scaling between input dimensions and model requirements.\n *\n * @param rawImageData - The raw image data to potentially resize.\n * @returns The processed mask image data, resized if necessary.\n */\n private getMaskImageData(rawImageData: Uint8ClampedArray): Uint8ClampedArray {\n const modelInput = this.config.mask.inputSize;\n const inputImage = this.config.input;\n\n // Check if resizing is needed based on configuration.\n if (modelInput.width === inputImage.width && modelInput.height === inputImage.height) {\n return rawImageData;\n }\n\n // Resize the image data.\n return resizeImage(\n rawImageData,\n inputImage.width,\n inputImage.height,\n modelInput.width,\n modelInput.height\n );\n }\n\n /**\n * Create the inference result object with appropriate data.\n * Handles both successful inference results and fallback cases.\n *\n * @param timestamp - The timestamp of the frame in milliseconds.\n * @param performedInference - Whether inference was actually performed for this frame.\n * @returns The inference result object containing mask data and metadata.\n */\n private createInferenceResult(\n timestamp: number,\n performedInference: boolean\n ): IFrameInferenceResult {\n if (!this.lastMaskResult) {\n return {\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n skipped: true,\n timestamp,\n // Stats will be added by the caller if needed\n };\n }\n\n return {\n facesAndLandmarks: this.lastMaskResult.facesAndLandmarks,\n gesture: this.lastMaskResult.gesture,\n motion: this.lastMaskResult.motion,\n skipped: !performedInference,\n timestamp,\n // Stats will be added by the caller if needed\n };\n }\n\n /**\n * Check if the pipeline is fully loaded and ready for processing.\n *\n * @returns True if the pipeline is loaded and ready, false otherwise.\n */\n public isLoaded(): boolean {\n return this.loaded;\n }\n\n /**\n * Load and initialize the pipeline components.\n * Creates the appropriate renderer and generator based on configuration.\n *\n * @returns Promise that resolves when all components are loaded and ready.\n * @throws Error if an unsupported renderer type is specified in the configuration.\n */\n public async load(): Promise<void> {\n switch (this.config.render.type) {\n case 'blur':\n this.renderer = new BlurRenderer(this.outputCanvas, this.config);\n break;\n case 'passthrough':\n this.renderer = new PassthroughRenderer(this.outputCanvas, this.config);\n break;\n case 'replacement':\n this.renderer = new ReplacementRenderer(this.outputCanvas, this.config);\n break;\n default:\n throw new Error('[ladon-ts] Renderer not implemented.');\n }\n\n await this.renderer.load();\n\n this.generator = new WorkerGenerator(this.config);\n await this.generator.load();\n\n this.loaded = true;\n }\n\n /**\n * Reset the pipeline state by clearing cached mask results.\n * Useful when switching between different processing modes or sources.\n */\n public reset(): void {\n this.lastMaskResult = undefined;\n }\n\n /**\n * Destroy the pipeline and clean up all resources.\n * Properly disposes of the renderer and generator to prevent memory leaks.\n *\n * @returns Promise that resolves when cleanup is complete.\n */\n public async destroy(): Promise<void> {\n this.reset();\n this.renderer?.destroy();\n await this.generator?.destroy();\n this.loaded = false;\n }\n}\n"],"names":["Pipeline","inputCanvas","outputCanvas","config","inputVideoElement","inputCanvasContext","timestamp","performInference","frameData","frameStartTime","preprocessingTime","modelInferenceTime","renderFrameData","preprocessStart","inferenceStart","rawImageData","maskImageData","postprocessStart","postprocessingTime","frameEndTime","totalFrameTime","result","_a","modelInput","inputImage","resizeImage","performedInference","BlurRenderer","PassthroughRenderer","ReplacementRenderer","WorkerGenerator","_b"],"mappings":";;;;;AAUO,MAAMA,EAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkCvC,YACYC,GACAC,GACQC,GACCC,GACnB;AAJU,SAAA,cAAAH,GACA,KAAA,eAAAC,GACQ,KAAA,SAAAC,GACC,KAAA,oBAAAC,GA9BrB,KAAQ,SAAS,IASjB,KAAQ,oBAAoB,IAG5B,KAAQ,sBAA6D;AAoBjE,UAAMC,IAAqB,KAAK,YAAY,WAAW,MAAM;AAAA,MACzD,OAAO;AAAA,MACP,oBAAoB;AAAA,IAAA,CACvB;AAED,QAAI,CAACA;AACK,YAAA,IAAI,MAAM,2CAA2C;AAE/D,SAAK,qBAAqBA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc9B,MAAa,QACTC,GACAC,IAAmB,IACnBC,GAC8B;AAE1B,IAAA,KAAK,qBAAqB,KAAK,uBAC/B,MAAM,KAAK,qBAIf,KAAK,oBAAoB;AAErB,QAAA;AACA,kBAAK,sBAAsB,KAAK;AAAA,QAC5BF;AAAA,QACAC;AAAA,QACAC;AAAA,MACJ,GACO,MAAM,KAAK;AAAA,IAAA,UACpB;AACE,WAAK,oBAAoB,IACzB,KAAK,sBAAsB;AAAA,IAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaJ,MAAc,qBACVF,GACAC,IAAmB,IACnBC,GAC8B;AACxB,UAAAC,IAAiB,YAAY,IAAI;AAEvC,QAAI,CAAC,KAAK,aAAa,CAAC,KAAK;AACnB,YAAA,IAAI,MAAM,oCAAoC;AAGxD,QAAIC,IAAoB,GACpBC,IAAqB,GACrBC;AAEA,QAAAL,KAAoB,CAAC,KAAK,gBAAgB;AAEpC,YAAAM,IAAkB,YAAY,IAAI;AAGxC,MAAAL,UAAc,KAAK,kBAAkB,IAGnBI,IAAA,KAAK,oBAAoBJ,CAAS,GAEhCE,IAAA,YAAY,QAAQG;AAGlC,YAAAC,IAAiB,YAAY,IAAI,GACjCC,IAAeP,GACfQ,IAAgB,KAAK,iBAAiBD,CAAY;AACxD,YAAM,KAAK,UAAU,QAAQC,GAAeV,CAAS,GACrD,KAAK,iBAAiB,MAAM,KAAK,UAAU,2BAA2BA,CAAS,GAC1DK,IAAA,YAAY,QAAQG;AAAA,IAAA;AAGzC,MAAAF,IAAkB,KAAK;AAIrB,UAAAK,IAAmB,YAAY,IAAI;AACzC,UAAM,KAAK,SAAS,OAAOL,GAAiB,KAAK,cAAc;AACzD,UAAAM,IAAqB,YAAY,IAAA,IAAQD,GAEzCE,IAAe,YAAY,IAAI,GAC/BC,IAAiBD,IAAeV,GAEhCY,IAAS,KAAK,sBAAsBf,GAAWC,CAAgB;AACrE,WAAAc,EAAO,QAAQ;AAAA,MACX,gBAAAD;AAAA,MACA,oBAAAT;AAAA,MACA,mBAAAD;AAAA,MACA,oBAAAQ;AAAA,MACA,gBAAAT;AAAA,MACA,cAAAU;AAAA,MACA,kBAAkB,CAACZ;AAAA,IACvB,GAEOc;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQH,oBAA+B;AACnC,WAAO,KAAK,mBAAmB;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,KAAK,OAAO,MAAM;AAAA,MAClB,KAAK,OAAO,MAAM;AAAA,IAAA,EACpB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAME,oBAAoBb,GAAiC;;AACzD,WAAIA,aAAqB,uBACjBc,IAAA,KAAK,oBAAL,gBAAAA,EAAsB,YAAWd,EAAU,WAC3C,KAAK,kBAAkB,IAAI,kBAAkBA,EAAU,MAAM,IAE5D,KAAA,gBAAgB,IAAIA,CAAS,GAC3B,KAAK,mBAETA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUH,iBAAiBO,GAAoD;AACnE,UAAAQ,IAAa,KAAK,OAAO,KAAK,WAC9BC,IAAa,KAAK,OAAO;AAG/B,WAAID,EAAW,UAAUC,EAAW,SAASD,EAAW,WAAWC,EAAW,SACnET,IAIJU;AAAA,MACHV;AAAA,MACAS,EAAW;AAAA,MACXA,EAAW;AAAA,MACXD,EAAW;AAAA,MACXA,EAAW;AAAA,IACf;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWI,sBACJjB,GACAoB,GACqB;AACjB,WAAC,KAAK,iBAWH;AAAA,MACH,mBAAmB,KAAK,eAAe;AAAA,MACvC,SAAS,KAAK,eAAe;AAAA,MAC7B,QAAQ,KAAK,eAAe;AAAA,MAC5B,SAAS,CAACA;AAAA,MACV,WAAApB;AAAA;AAAA,IAEJ,IAjBW;AAAA,MACH,mBAAmB,EAAE,MAAM,IAAI,aAAa,CAAC,GAAG,MAAM,GAAG;AAAA,MACzD,SAAS,IAAI,aAAa,CAAC;AAAA,MAC3B,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,WAAAA;AAAA;AAAA,IAEJ;AAAA,EAUJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQG,WAAoB;AACvB,WAAO,KAAK;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUhB,MAAa,OAAsB;AACvB,YAAA,KAAK,OAAO,OAAO,MAAM;AAAA,MAC7B,KAAK;AACD,aAAK,WAAW,IAAIqB,EAAa,KAAK,cAAc,KAAK,MAAM;AAC/D;AAAA,MACJ,KAAK;AACD,aAAK,WAAW,IAAIC,EAAoB,KAAK,cAAc,KAAK,MAAM;AACtE;AAAA,MACJ,KAAK;AACD,aAAK,WAAW,IAAIC,EAAoB,KAAK,cAAc,KAAK,MAAM;AACtE;AAAA,MACJ;AACU,cAAA,IAAI,MAAM,sCAAsC;AAAA,IAAA;AAGxD,UAAA,KAAK,SAAS,KAAK,GAEzB,KAAK,YAAY,IAAIC,EAAgB,KAAK,MAAM,GAC1C,MAAA,KAAK,UAAU,KAAK,GAE1B,KAAK,SAAS;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOX,QAAc;AACjB,SAAK,iBAAiB;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS1B,MAAa,UAAyB;;AAClC,SAAK,MAAM,IACXR,IAAA,KAAK,aAAL,QAAAA,EAAe,WACT,QAAAS,IAAA,KAAK,cAAL,gBAAAA,EAAgB,YACtB,KAAK,SAAS;AAAA,EAAA;AAEtB;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "5.9.
|
|
1
|
+
export declare const LIB_VERSION = "5.9.1";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sources":["../../../src/lib/version.ts"],"sourcesContent":["export const LIB_VERSION = '5.9.
|
|
1
|
+
{"version":3,"file":"version.js","sources":["../../../src/lib/version.ts"],"sourcesContent":["export const LIB_VERSION = '5.9.1';\n"],"names":["LIB_VERSION"],"mappings":"AAAO,MAAMA,IAAc;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cisco Ladon-TS
|
|
3
3
|
* Copyright (c) Cisco Systems, Inc. All rights reserved.
|
|
4
|
-
* Build timestamp: July
|
|
4
|
+
* Build timestamp: July 2, 2025 at 09:45:43 PM UTC
|
|
5
5
|
*/
|
|
6
6
|
(function(){"use strict";var _documentCurrentScript=typeof document<"u"?document.currentScript:null;self.document={baseURI:location.origin};const originalConsoleLog=console.log,originalConsoleWarn=console.warn,originalConsoleError=console.error;console.log=(...e)=>{postMessage({type:"log",message:e.join(" "),severity:"log"}),originalConsoleLog(...e)},console.warn=(...e)=>{postMessage({type:"log",message:e.join(" "),severity:"warn"}),originalConsoleWarn(...e)},console.error=(...e)=>{postMessage({type:"log",message:e.join(" "),severity:"error"}),originalConsoleError(...e)};/*!
|
|
7
7
|
* ONNX Runtime Web v1.20.1
|