@zappar/zappar-cv 3.2.0-beta.2 → 3.3.0-beta.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/README.md CHANGED
@@ -18,8 +18,8 @@ npm i @zappar/zappar-cv
18
18
 
19
19
  You can use our CDN from within your HTML:
20
20
  ```
21
- <script src="https://libs.zappar.com/zappar-cv/3.2.0-beta.2/zappar-cv.js"></script>
21
+ <script src="https://libs.zappar.com/zappar-cv/3.3.0-beta.0/zappar-cv.js"></script>
22
22
  ```
23
23
 
24
24
  Or you can download and host our standalone JavaScript bundle:
25
- [https://libs.zappar.com/zappar-cv/3.2.0-beta.2/zappar-cv.zip](https://libs.zappar.com/zappar-cv/3.2.0-beta.2/zappar-cv.zip)
25
+ [https://libs.zappar.com/zappar-cv/3.3.0-beta.0/zappar-cv.zip](https://libs.zappar.com/zappar-cv/3.3.0-beta.0/zappar-cv.zip)
@@ -1,4 +1,4 @@
1
- import { CameraFrameData } from "./camera-frame-data";
1
+ import { CameraFrameData, CameraFrameDataRGB } from "./camera-frame-data";
2
2
  import { zappar_face_mesh_t, zappar_face_tracker_t, zappar_world_tracker_t, zappar_pipeline_t, zappar_image_tracker_t, zappar_sequence_source_t } from "./gen/zappar";
3
3
  export declare type zappar_html_element_source_t = number & {
4
4
  _: 'zappar_html_element_source_t';
@@ -23,6 +23,8 @@ export interface Additional {
23
23
  pipeline_draw_face_project(pipeline: zappar_pipeline_t, drawwMatrix: Float32Array, vertices: Float32Array, uvMatrix: Float32Array, uvs: Float32Array, indices: Uint16Array, texture: WebGLTexture): void;
24
24
  pipeline_camera_frame_data_raw_enabled_set(pipeline: zappar_pipeline_t, enabled: boolean): void;
25
25
  pipeline_camera_frame_data_raw(pipeline: zappar_pipeline_t): Promise<CameraFrameData | undefined>;
26
+ pipeline_camera_frame_data_rgb_enabled_set(pipeline: zappar_pipeline_t, enabled: boolean): void;
27
+ pipeline_camera_frame_data_rgb(pipeline: zappar_pipeline_t): CameraFrameDataRGB | undefined;
26
28
  draw_plane(gl: WebGLRenderingContext, projectionMatrix: Float32Array, cameraMatrix: Float32Array, targetMatrix: Float32Array, texture: string): void;
27
29
  draw_grid(gl: WebGLRenderingContext, projectionMatrix: Float32Array, cameraMatrix: Float32Array, targetMatrix: Float32Array): void;
28
30
  draw_axis(gl: WebGLRenderingContext, projectionMatrix: Float32Array, cameraMatrix: Float32Array, targetMatrix: Float32Array): void;
@@ -2,10 +2,14 @@ export declare class AndroidBridgeMessageHandler {
2
2
  private _nativePort;
3
3
  private _messageId;
4
4
  private _replyResolvers;
5
+ private _queuedMessages;
5
6
  static IsSupported(): boolean;
7
+ private static _instance;
8
+ static SharedInstance(): AndroidBridgeMessageHandler;
6
9
  postMessage(message: string): Promise<any>;
7
10
  private _processMessage;
8
11
  private _processStringMessage;
9
12
  private _processArrayBufferMessage;
13
+ private _initRequested;
10
14
  private _initPort;
11
15
  }
@@ -38,6 +38,7 @@ export class AndroidBridgeMessageHandler {
38
38
  constructor() {
39
39
  this._messageId = 0;
40
40
  this._replyResolvers = new Map();
41
+ this._queuedMessages = [];
41
42
  this._processMessage = (msg) => {
42
43
  if (typeof msg.data === "string") {
43
44
  traceStart("ABMH: processStringMessage");
@@ -51,25 +52,32 @@ export class AndroidBridgeMessageHandler {
51
52
  traceEnd();
52
53
  }
53
54
  };
55
+ this._initRequested = false;
54
56
  }
55
57
  static IsSupported() {
56
58
  let hasAndroidInterface = !!(globalThis.zprCameraBridge);
57
59
  return hasAndroidInterface;
58
60
  }
61
+ static SharedInstance() {
62
+ if (AndroidBridgeMessageHandler._instance == null) {
63
+ AndroidBridgeMessageHandler._instance = new AndroidBridgeMessageHandler();
64
+ }
65
+ return AndroidBridgeMessageHandler._instance;
66
+ }
59
67
  postMessage(message) {
60
68
  return __awaiter(this, void 0, void 0, function* () {
61
69
  traceStart("ABMH: postMessage");
62
- if (!this._nativePort) {
63
- let portReady = this._initPort();
64
- traceEnd();
65
- yield portReady;
66
- traceStart("ABMH: postMessage continuation");
67
- }
68
70
  let fullMsg = `zpr:${this._messageId}:${message}`;
69
71
  let reply = new Promise((resolve, reject) => {
70
72
  this._replyResolvers.set(this._messageId, { resolve, reject });
71
73
  });
72
- this._nativePort.postMessage(fullMsg);
74
+ if (!this._nativePort) {
75
+ this._queuedMessages.push(fullMsg);
76
+ this._initPort();
77
+ }
78
+ else {
79
+ this._nativePort.postMessage(fullMsg);
80
+ }
73
81
  this._messageId++;
74
82
  traceEnd();
75
83
  return reply;
@@ -150,18 +158,28 @@ export class AndroidBridgeMessageHandler {
150
158
  replyResolvers.resolve(msgData);
151
159
  }
152
160
  _initPort() {
153
- return new Promise(resolve => {
154
- let listener = (msg) => {
155
- if (msg.data === "zprCameraBridgePort" && msg.ports.length > 0) {
156
- this._nativePort = msg.ports[0];
157
- window.removeEventListener("message", listener);
158
- window.addEventListener("message", this._processMessage);
159
- resolve();
161
+ // Ensure we only call the request once
162
+ if (this._initRequested)
163
+ return;
164
+ this._initRequested = true;
165
+ // The one-time listener to receive the port from native ZapparCameraBridge
166
+ const listener = (msg) => {
167
+ if (msg.data === "zprCameraBridgePort" && msg.ports.length > 0) {
168
+ this._nativePort = msg.ports[0];
169
+ // Post initial messages in the order they were queued
170
+ for (const msg of this._queuedMessages) {
171
+ this._nativePort.postMessage(msg);
160
172
  }
161
- };
162
- window.addEventListener("message", listener);
163
- let origin = window.origin || document.location.origin;
164
- window.zprCameraBridge.requestMessageChannel(origin);
165
- });
173
+ this._queuedMessages = [];
174
+ // Remove this listener, add the main processMessage one
175
+ window.removeEventListener("message", listener);
176
+ window.addEventListener("message", this._processMessage);
177
+ }
178
+ };
179
+ // Use the JSInterface from ZapparCameraBridge to request a message channel
180
+ window.addEventListener("message", listener);
181
+ let origin = window.origin || document.location.origin;
182
+ window.zprCameraBridge.requestMessageChannel(origin);
166
183
  }
167
184
  }
185
+ AndroidBridgeMessageHandler._instance = null;
@@ -97,7 +97,7 @@ export class BridgedCameraSource extends Source {
97
97
  pipeline.motionAttitudeSubmitInt(timeStamp, 0, ev.alpha, ev.beta, ev.gamma);
98
98
  };
99
99
  if (AndroidBridgeMessageHandler.IsSupported()) {
100
- this._messageHandler = new AndroidBridgeMessageHandler();
100
+ this._messageHandler = AndroidBridgeMessageHandler.SharedInstance();
101
101
  }
102
102
  else {
103
103
  this._messageHandler = (_b = (_a = window.webkit) === null || _a === void 0 ? void 0 : _a.messageHandlers) === null || _b === void 0 ? void 0 : _b.bridgedCamera;
@@ -1,5 +1,11 @@
1
- export interface CameraFrameData {
1
+ /// <reference types="dom-webcodecs" />
2
+ export interface BaseFrameData {
2
3
  width: number;
3
4
  height: number;
5
+ }
6
+ export interface CameraFrameData extends BaseFrameData {
4
7
  data: ArrayBuffer;
5
8
  }
9
+ export interface CameraFrameDataRGB extends BaseFrameData {
10
+ frame: ImageBitmap | VideoFrame | ImageData;
11
+ }
@@ -16,6 +16,12 @@ export declare class HTMLElementSource extends Source {
16
16
  private _cameraModel;
17
17
  private _profile;
18
18
  private _waitingForFrame;
19
+ private _rgbOffscreenCanvas;
20
+ private _rgbOffscreenContext;
21
+ private _rgbDomCanvas;
22
+ private _rgbDomContext;
23
+ private _currentRgbFrame;
24
+ private _isVideoElement;
19
25
  static createVideoElementSource(p: zappar_pipeline_t, element: HTMLVideoElement | HTMLImageElement): zappar_html_element_source_t;
20
26
  static getVideoElementSource(m: zappar_html_element_source_t): HTMLElementSource | undefined;
21
27
  constructor(_video: HTMLVideoElement | HTMLImageElement, _pipeline: zappar_pipeline_t);
@@ -30,4 +36,7 @@ export declare class HTMLElementSource extends Source {
30
36
  private _processFrame;
31
37
  uploadGL(): void;
32
38
  setProfile(p: camera_profile_t): void;
39
+ private _generateRGBFrame;
40
+ private _generateOffscreenRgbFrame;
41
+ private _generateDomRgbFrame;
33
42
  }
@@ -3,7 +3,7 @@ import { Pipeline } from "./pipeline";
3
3
  import { Source } from "./source";
4
4
  import { profile } from "./profile";
5
5
  import { mat4 } from "gl-matrix";
6
- import { zcout } from "./loglevel";
6
+ import { zcout, zcerr } from "./loglevel";
7
7
  import { ImageProcessGL } from "./image-process-gl";
8
8
  let latest = 1;
9
9
  let byId = new Map();
@@ -22,10 +22,14 @@ export class HTMLElementSource extends Source {
22
22
  this._cameraModel = new Float32Array([300, 300, 160, 120, 0, 0]);
23
23
  this._profile = camera_profile_t.DEFAULT;
24
24
  this._waitingForFrame = false;
25
+ this._rgbOffscreenContext = null;
26
+ this._rgbDomContext = null;
27
+ this._isVideoElement = false;
25
28
  this._lastPresentedFrames = -1;
26
29
  mat4.fromScaling(this._cameraToDeviceTransformUserFacing, [-1, 1, -1]);
27
30
  let video = this._video;
28
- if (this._video instanceof HTMLVideoElement) {
31
+ this._isVideoElement = video instanceof HTMLVideoElement;
32
+ if (this._isVideoElement) {
29
33
  video.addEventListener("loadedmetadata", () => { this._hadFrames = true; });
30
34
  }
31
35
  else {
@@ -56,6 +60,11 @@ export class HTMLElementSource extends Source {
56
60
  p.onGLContextReset.unbind(this._resetGLContext);
57
61
  this.pause();
58
62
  this._resetGLContext();
63
+ this._currentRgbFrame = undefined;
64
+ this._rgbDomCanvas = undefined;
65
+ this._rgbDomContext = null;
66
+ this._rgbOffscreenCanvas = undefined;
67
+ this._rgbOffscreenContext = null;
59
68
  }
60
69
  pause() {
61
70
  this._isPaused = true;
@@ -138,6 +147,8 @@ export class HTMLElementSource extends Source {
138
147
  }
139
148
  if (!this._currentVideoTexture)
140
149
  return undefined;
150
+ if (pipeline.getCameraFrameDataRGBEnabled())
151
+ this._currentRgbFrame = this._generateRGBFrame();
141
152
  this._imageProcessor.uploadFrame(this._currentVideoTexture, this._video, rotation, this._isUserFacing, this._profile);
142
153
  this._requestVideoFrameCallback();
143
154
  this._isUploadFrame = !this._isUploadFrame;
@@ -164,7 +175,12 @@ export class HTMLElementSource extends Source {
164
175
  this._cameraModel[1] = focalLength;
165
176
  this._cameraModel[2] = dataWidth * 0.5;
166
177
  this._cameraModel[3] = dataHeight * 0.5;
167
- return Object.assign(Object.assign({}, this._imageProcessor.readFrame(tex, pixels, this._profile)), { cameraModel: this._cameraModel, cameraSource: this, cameraToDevice: (this._isUserFacing ? this._cameraToDeviceTransformUserFacing : this._cameraToDeviceTransform) });
178
+ const info = Object.assign(Object.assign({}, this._imageProcessor.readFrame(tex, pixels, this._profile)), { cameraModel: this._cameraModel, cameraSource: this, cameraToDevice: (this._isUserFacing ? this._cameraToDeviceTransformUserFacing : this._cameraToDeviceTransform) });
179
+ if (this._currentRgbFrame) {
180
+ info.rgbFrame = this._currentRgbFrame;
181
+ this._currentRgbFrame = undefined;
182
+ }
183
+ return info;
168
184
  }
169
185
  uploadGL() {
170
186
  // No-op as already uploaded
@@ -172,4 +188,57 @@ export class HTMLElementSource extends Source {
172
188
  setProfile(p) {
173
189
  this._profile = p;
174
190
  }
191
+ _generateRGBFrame() {
192
+ const width = this._isVideoElement ? this._video.videoWidth : this._video.naturalWidth;
193
+ const height = this._isVideoElement ? this._video.videoHeight : this._video.naturalHeight;
194
+ if (!(width > 0 && height > 0))
195
+ return undefined;
196
+ return profile.offscreenCanvasSupported
197
+ ? this._generateOffscreenRgbFrame(width, height)
198
+ : this._generateDomRgbFrame(width, height);
199
+ }
200
+ _generateOffscreenRgbFrame(width, height) {
201
+ var _a;
202
+ if (!this._rgbOffscreenCanvas) {
203
+ this._rgbOffscreenCanvas = new OffscreenCanvas(width, height);
204
+ this._rgbOffscreenContext = this._rgbOffscreenCanvas.getContext('2d', {
205
+ alpha: false,
206
+ willReadFrequently: true
207
+ });
208
+ }
209
+ else if (this._rgbOffscreenCanvas.width !== width || this._rgbOffscreenCanvas.height !== height) {
210
+ this._rgbOffscreenCanvas.width = width;
211
+ this._rgbOffscreenCanvas.height = height;
212
+ }
213
+ (_a = this._rgbOffscreenContext) === null || _a === void 0 ? void 0 : _a.drawImage(this._video, 0, 0, width, height);
214
+ try {
215
+ return this._rgbOffscreenCanvas.transferToImageBitmap();
216
+ }
217
+ catch (e) {
218
+ zcerr(`Failed to generate RGB frame: ${e}`);
219
+ return undefined;
220
+ }
221
+ }
222
+ _generateDomRgbFrame(width, height) {
223
+ var _a, _b;
224
+ if (!this._rgbDomCanvas) {
225
+ this._rgbDomCanvas = document.createElement('canvas');
226
+ this._rgbDomContext = this._rgbDomCanvas.getContext('2d', {
227
+ alpha: false,
228
+ willReadFrequently: true
229
+ });
230
+ }
231
+ else if (this._rgbDomCanvas.width !== width || this._rgbDomCanvas.height !== height) {
232
+ this._rgbDomCanvas.width = width;
233
+ this._rgbDomCanvas.height = height;
234
+ }
235
+ (_a = this._rgbDomContext) === null || _a === void 0 ? void 0 : _a.drawImage(this._video, 0, 0, width, height);
236
+ try {
237
+ return (_b = this._rgbDomContext) === null || _b === void 0 ? void 0 : _b.getImageData(0, 0, width, height);
238
+ }
239
+ catch (e) {
240
+ zcerr(`Failed to generate RGB frame: ${e}`);
241
+ return undefined;
242
+ }
243
+ }
175
244
  }
@@ -286,8 +286,6 @@ export class ImageBitmapCameraSource extends Source {
286
286
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, info.frame);
287
287
  gl.bindTexture(gl.TEXTURE_2D, null);
288
288
  info.texture = texture;
289
- info.frame.close();
290
- delete info.frame;
291
289
  }
292
290
  }
293
291
  ImageBitmapCameraSource.USER_DEFAULT_DEVICE_ID = "Simulated User Default Device ID: a908df7f-5661-4d20-b227-a1c15d2fdb4b";
@@ -323,8 +323,6 @@ export class MSTPCameraSource extends Source {
323
323
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, info.frame);
324
324
  gl.bindTexture(gl.TEXTURE_2D, previousBoundTexture);
325
325
  info.texture = texture;
326
- info.frame.close();
327
- delete info.frame;
328
326
  }
329
327
  }
330
328
  MSTPCameraSource.USER_DEFAULT_DEVICE_ID = "Simulated User Default Device ID: a908df7f-5661-4d20-b227-a1c15d2fdb4b";
package/lib/native.js CHANGED
@@ -277,7 +277,7 @@ export function initialize(opts) {
277
277
  return;
278
278
  }
279
279
  (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.drawImageTargetPreview(projectionMatrix, cameraMatrix, targetMatrix, indx, obj);
280
- }, projection_matrix_from_camera_model_and_size: projectionMatrixFromModelAndSize, projection_matrix_from_camera_model_and_size_ext: projectionMatrixFromModelAndSize, pipeline_process_gl: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.processGL(); }, pipeline_gl_context_set: (p, gl, texturePool) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.glContextSet(gl, texturePool); }, pipeline_gl_context_lost: (p) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.glContextLost(); }, pipeline_camera_frame_upload_gl: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.uploadGL(); }, pipeline_camera_frame_texture_gl: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.cameraFrameTexture(); }, pipeline_camera_frame_texture_matrix: (p, sw, sh, mirror) => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.cameraFrameTextureMatrix(sw, sh, mirror)) || mat4.create(); }, pipeline_camera_frame_user_facing: p => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.cameraFrameUserFacing()) || false; }, pipeline_camera_pose_default: () => mat4.create(), pipeline_camera_pose_with_attitude: (p, mirror) => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.cameraPoseWithAttitude(mirror)) || mat4.create(); }, pipeline_camera_pose_with_origin: (p, o) => { let res = mat4.create(); mat4.invert(res, o); return res; }, pipeline_sequence_record_clear: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordClear(); }, pipeline_sequence_record_start: (p, expectedFrames) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordStart(expectedFrames); }, pipeline_sequence_record_stop: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordStop(); }, pipeline_sequence_record_device_attitude_matrices_set: (p, v) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordDeviceAttitudeMatrices(v); }, pipeline_sequence_record_data: p => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordData()) || new Uint8Array(0); }, pipeline_sequence_record_data_size: p => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordData().byteLength) || 0; }, pipeline_camera_frame_data_raw: p => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.getCameraFrameDataRaw()) || Promise.reject(); }, pipeline_camera_frame_data_raw_enabled_set: (p, v) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.setCameraFrameDataRawEnabled(v); }, instant_world_tracker_anchor_pose_camera_relative: (o, mirror) => {
280
+ }, projection_matrix_from_camera_model_and_size: projectionMatrixFromModelAndSize, projection_matrix_from_camera_model_and_size_ext: projectionMatrixFromModelAndSize, pipeline_process_gl: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.processGL(); }, pipeline_gl_context_set: (p, gl, texturePool) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.glContextSet(gl, texturePool); }, pipeline_gl_context_lost: (p) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.glContextLost(); }, pipeline_camera_frame_upload_gl: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.uploadGL(); }, pipeline_camera_frame_texture_gl: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.cameraFrameTexture(); }, pipeline_camera_frame_texture_matrix: (p, sw, sh, mirror) => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.cameraFrameTextureMatrix(sw, sh, mirror)) || mat4.create(); }, pipeline_camera_frame_user_facing: p => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.cameraFrameUserFacing()) || false; }, pipeline_camera_pose_default: () => mat4.create(), pipeline_camera_pose_with_attitude: (p, mirror) => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.cameraPoseWithAttitude(mirror)) || mat4.create(); }, pipeline_camera_pose_with_origin: (p, o) => { let res = mat4.create(); mat4.invert(res, o); return res; }, pipeline_sequence_record_clear: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordClear(); }, pipeline_sequence_record_start: (p, expectedFrames) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordStart(expectedFrames); }, pipeline_sequence_record_stop: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordStop(); }, pipeline_sequence_record_device_attitude_matrices_set: (p, v) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordDeviceAttitudeMatrices(v); }, pipeline_sequence_record_data: p => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordData()) || new Uint8Array(0); }, pipeline_sequence_record_data_size: p => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.sequenceRecordData().byteLength) || 0; }, pipeline_camera_frame_data_raw: p => { var _a; return ((_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.getCameraFrameDataRaw()) || Promise.reject(); }, pipeline_camera_frame_data_raw_enabled_set: (p, v) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.setCameraFrameDataRawEnabled(v); }, pipeline_camera_frame_data_rgb: p => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.getCameraFrameDataRGB(); }, pipeline_camera_frame_data_rgb_enabled_set: (p, v) => { var _a; return (_a = Pipeline.get(p)) === null || _a === void 0 ? void 0 : _a.setCameraFrameDataRGBEnabled(v); }, instant_world_tracker_anchor_pose_camera_relative: (o, mirror) => {
281
281
  let res = applyScreenCounterRotation(undefined, c.impl.instant_world_tracker_anchor_pose_raw(o));
282
282
  if (mirror) {
283
283
  let scale = mat4.create();
@@ -456,8 +456,8 @@ export function initialize(opts) {
456
456
  }
457
457
  }
458
458
  }
459
- if (!anchor_pose) {
460
- zcwarn("unable for find anchor with id", anchor_id);
459
+ if (!anchor_pose || anchor_pose.length !== 16) {
460
+ zcwarn("unable for find valid pose for anchor with id", anchor_id);
461
461
  return;
462
462
  }
463
463
  const pose = mat4.create();
package/lib/pipeline.d.ts CHANGED
@@ -9,7 +9,7 @@ import { FaceMesh } from "./facemesh";
9
9
  import { Event } from "./event";
10
10
  import { ImageTracker } from "./imagetracker";
11
11
  import { zappar } from "./gen/zappar-bridge";
12
- import { CameraFrameData } from "./camera-frame-data";
12
+ import { CameraFrameData, CameraFrameDataRGB } from "./camera-frame-data";
13
13
  export declare class Pipeline {
14
14
  private _client;
15
15
  private _impl;
@@ -33,6 +33,7 @@ export declare class Pipeline {
33
33
  private _cameraFrameDataResolves;
34
34
  private _cameraFrameDataRejects;
35
35
  private _cameraFrameDataEnabled;
36
+ private _cameraFrameDataRGBEnabled;
36
37
  onGLContextReset: Event;
37
38
  static create(client: zappar, mgr: MsgManager): zappar_pipeline_t;
38
39
  static get(p: zappar_pipeline_t): Pipeline | undefined;
@@ -47,6 +48,9 @@ export declare class Pipeline {
47
48
  sequenceRecordClear(): void;
48
49
  sequenceRecordDeviceAttitudeMatrices(v: boolean): void;
49
50
  getVideoTexture(): WebGLTexture | undefined;
51
+ getCameraFrameDataRGB(): CameraFrameDataRGB | undefined;
52
+ setCameraFrameDataRGBEnabled(e: boolean): void;
53
+ getCameraFrameDataRGBEnabled(): boolean;
50
54
  getCameraFrameDataRaw(): Promise<CameraFrameData | undefined>;
51
55
  setCameraFrameDataRawEnabled(e: boolean): void;
52
56
  destroy(): void;
package/lib/pipeline.js CHANGED
@@ -28,6 +28,7 @@ export class Pipeline {
28
28
  this._cameraFrameDataResolves = new Map();
29
29
  this._cameraFrameDataRejects = new Map();
30
30
  this._cameraFrameDataEnabled = false;
31
+ this._cameraFrameDataRGBEnabled = false;
31
32
  this.onGLContextReset = new Event();
32
33
  }
33
34
  static create(client, mgr) {
@@ -51,7 +52,7 @@ export class Pipeline {
51
52
  this.cleanOldFrames();
52
53
  }
53
54
  cleanOldFrames() {
54
- var _a, _b, _c, _d;
55
+ var _a, _b, _c, _d, _e, _f;
55
56
  let currentToken = this._client.pipeline_camera_frame_user_data(this._impl);
56
57
  if (!currentToken)
57
58
  return;
@@ -60,7 +61,17 @@ export class Pipeline {
60
61
  if (t[1].texture)
61
62
  this.videoTextures.push(t[1].texture);
62
63
  (_b = (_a = t[1].frame) === null || _a === void 0 ? void 0 : _a.close) === null || _b === void 0 ? void 0 : _b.call(_a);
63
- (_d = (_c = t[1].cameraSource).recycle) === null || _d === void 0 ? void 0 : _d.call(_c, t[1]);
64
+ if (t[1].frame !== t[1].rgbFrame) {
65
+ if (t[1].rgbFrame instanceof ImageData) {
66
+ // auto gc'd
67
+ }
68
+ else {
69
+ (_d = (_c = t[1].rgbFrame) === null || _c === void 0 ? void 0 : _c.close) === null || _d === void 0 ? void 0 : _d.call(_c);
70
+ }
71
+ }
72
+ t[1].frame = undefined;
73
+ t[1].rgbFrame = undefined;
74
+ (_f = (_e = t[1].cameraSource).recycle) === null || _f === void 0 ? void 0 : _f.call(_e, t[1]);
64
75
  if (t[1].data) {
65
76
  this.cameraPixelArrays.push(t[1].data);
66
77
  t[1].data = undefined;
@@ -135,6 +146,34 @@ export class Pipeline {
135
146
  getVideoTexture() {
136
147
  return this.videoTextures.pop();
137
148
  }
149
+ getCameraFrameDataRGB() {
150
+ if (!this._cameraFrameDataRGBEnabled)
151
+ return undefined;
152
+ const info = this.getCurrentCameraInfo();
153
+ if (!info || !info.rgbFrame)
154
+ return undefined;
155
+ let width = 0;
156
+ let height = 0;
157
+ if (info.rgbFrame instanceof VideoFrame) {
158
+ width = info.rgbFrame.displayWidth;
159
+ height = info.rgbFrame.displayHeight;
160
+ }
161
+ else {
162
+ width = info.rgbFrame.width;
163
+ height = info.rgbFrame.height;
164
+ }
165
+ return {
166
+ frame: info.rgbFrame,
167
+ width,
168
+ height,
169
+ };
170
+ }
171
+ setCameraFrameDataRGBEnabled(e) {
172
+ this._cameraFrameDataRGBEnabled = e;
173
+ }
174
+ getCameraFrameDataRGBEnabled() {
175
+ return this._cameraFrameDataRGBEnabled;
176
+ }
138
177
  getCameraFrameDataRaw() {
139
178
  if (!this._cameraFrameDataEnabled)
140
179
  throw new Error('Raw camera frame data is not enabled.');
@@ -297,6 +336,7 @@ export class Pipeline {
297
336
  cameraToDevice: msg.cameraToDevice,
298
337
  cameraSource,
299
338
  remoteToken: msg.token,
339
+ rgbFrame: this._cameraFrameDataRGBEnabled ? msg.d : undefined,
300
340
  });
301
341
  this.cleanOldFrames();
302
342
  }
@@ -309,6 +349,8 @@ export class Pipeline {
309
349
  data.frame = msg.frame;
310
350
  data.userFacing = msg.userFacing;
311
351
  data.uvTransform = msg.uvTransform;
352
+ if (this._cameraFrameDataRGBEnabled)
353
+ data.rgbFrame = msg.frame;
312
354
  this.tokensInFlight--;
313
355
  this.cleanOldFrames();
314
356
  }
package/lib/profile.d.ts CHANGED
@@ -20,4 +20,5 @@ export declare let profile: {
20
20
  forceWindowOrientation: boolean;
21
21
  intervalMultiplier: number;
22
22
  trustSensorIntervals: boolean;
23
+ offscreenCanvasSupported: boolean;
23
24
  };
package/lib/profile.js CHANGED
@@ -23,6 +23,7 @@ export let profile = {
23
23
  forceWindowOrientation: false,
24
24
  intervalMultiplier: 1,
25
25
  trustSensorIntervals: false,
26
+ offscreenCanvasSupported: typeof globalThis.OffscreenCanvas !== "undefined",
26
27
  };
27
28
  if (typeof window !== "undefined") {
28
29
  window["zeeProfile"] = profile;
package/lib/source.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /// <reference types="dom-webcodecs" />
2
2
  export interface CameraFrameInfo {
3
+ rgbFrame?: ImageBitmap | VideoFrame | ImageData;
3
4
  data?: ArrayBuffer;
4
5
  texture: WebGLTexture | undefined;
5
6
  dataWidth: number;
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "3.2.0-beta.2";
1
+ export declare const VERSION = "3.3.0-beta.0";
package/lib/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "3.2.0-beta.2";
1
+ export const VERSION = "3.3.0-beta.0";
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zappar/zappar-cv",
3
- "version": "3.2.0-beta.2",
3
+ "version": "3.3.0-beta.0",
4
4
  "description": "Zappar's core computer vision library, supporting image, face and world tracking.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -31,7 +31,6 @@
31
31
  "devDependencies": {
32
32
  "@playwright/test": "^1.48.2",
33
33
  "@types/dom-mediacapture-transform": "0.1.1",
34
- "@types/dom-webcodecs": "0.1.2",
35
34
  "@types/node": "14.14.7",
36
35
  "@types/offscreencanvas": "2019.6.4",
37
36
  "@types/pngjs": "6.0.0",
@@ -52,6 +51,7 @@
52
51
  "dependencies": {
53
52
  "@types/w3c-generic-sensor": "^1.0.9",
54
53
  "gl-matrix": "3.4.3",
55
- "ua-parser-js": "1.0.33"
54
+ "ua-parser-js": "1.0.33",
55
+ "@types/dom-webcodecs": "0.1.2"
56
56
  }
57
57
  }