@zappar/zappar-cv 0.4.0-beta.1 → 0.4.0-beta.10

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +79 -34
  2. package/README.md +2 -2
  3. package/lib/additional.d.ts +2 -1
  4. package/lib/camera-source-map.d.ts +10 -0
  5. package/lib/camera-source-map.js +40 -0
  6. package/lib/camera-source.d.ts +2 -5
  7. package/lib/camera-source.js +3 -13
  8. package/lib/compatibility.js +1 -1
  9. package/lib/drawcamera.js +2 -1
  10. package/lib/gen/zappar-client.js +6 -16
  11. package/lib/gen/zappar-cwrap.js +37 -28
  12. package/lib/gen/zappar-native.d.ts +11 -1
  13. package/lib/gen/zappar-native.js +13 -1
  14. package/lib/gen/zappar-server.js +1 -5
  15. package/lib/gen/zappar.d.ts +12 -0
  16. package/lib/gen/zappar.js +5 -3
  17. package/lib/gfx.d.ts +1 -0
  18. package/lib/gfx.js +4 -0
  19. package/lib/gl-state-manager.d.ts +9 -0
  20. package/lib/gl-state-manager.js +35 -0
  21. package/lib/html-element-source.d.ts +3 -20
  22. package/lib/html-element-source.js +19 -263
  23. package/lib/image-process-gl.d.ts +37 -0
  24. package/lib/image-process-gl.js +298 -0
  25. package/lib/imagebitmap-camera-source.d.ts +36 -0
  26. package/lib/imagebitmap-camera-source.js +277 -0
  27. package/lib/imagetracker.d.ts +28 -0
  28. package/lib/imagetracker.js +119 -0
  29. package/lib/index.d.ts +1 -1
  30. package/lib/mstp-camera-source.d.ts +29 -0
  31. package/lib/mstp-camera-source.js +230 -0
  32. package/lib/native.js +119 -8
  33. package/lib/pipeline.d.ts +13 -3
  34. package/lib/pipeline.js +95 -26
  35. package/lib/profile.d.ts +2 -0
  36. package/lib/profile.js +55 -44
  37. package/lib/riff-reader.d.ts +18 -0
  38. package/lib/riff-reader.js +56 -0
  39. package/lib/sequencerecorder.d.ts +1 -0
  40. package/lib/sequencerecorder.js +11 -0
  41. package/lib/sequencesource.d.ts +7 -1
  42. package/lib/sequencesource.js +89 -47
  43. package/lib/source.d.ts +6 -4
  44. package/lib/version.d.ts +1 -1
  45. package/lib/version.js +1 -1
  46. package/lib/worker-client.js +0 -5
  47. package/lib/worker-imagebitmap.d.ts +5 -0
  48. package/lib/worker-imagebitmap.js +63 -0
  49. package/lib/worker-server.d.ts +0 -5
  50. package/lib/worker-server.js +120 -30
  51. package/lib/workerinterface.d.ts +47 -1
  52. package/lib/zcv.js +117 -135
  53. package/lib/zcv.wasm +0 -0
  54. package/package.json +34 -31
  55. package/umd/e9486c1cdadb21608a4f7e2fa3be9517.wasm +0 -0
  56. package/umd/zappar-cv.js +1 -9
  57. package/umd/zappar-cv.worker.js +1 -1
  58. package/lib/bundleworker-mainthread.d.ts +0 -2
  59. package/lib/bundleworker-mainthread.js +0 -36
  60. package/lib/bundleworker-worker.d.ts +0 -3
  61. package/lib/bundleworker-worker.js +0 -47
  62. package/umd/5dd5cacd27e6e7da828f.bundleworker.js +0 -1
  63. package/umd/a20150d17b0290cadaa6cb9911ab9500.wasm +0 -0
package/lib/pipeline.js CHANGED
@@ -10,7 +10,9 @@ const drawplane_1 = require("./drawplane");
10
10
  const event_1 = require("./event");
11
11
  const loglevel_1 = require("./loglevel");
12
12
  const sequencerecorder_1 = require("./sequencerecorder");
13
+ const camera_source_map_1 = require("./camera-source-map");
13
14
  let byId = new Map();
15
+ let identity = gl_matrix_1.mat4.create();
14
16
  class Pipeline {
15
17
  constructor(_client, _impl, _mgr) {
16
18
  this._client = _client;
@@ -23,6 +25,7 @@ class Pipeline {
23
25
  this.videoTextures = [];
24
26
  this.cameraPixelArrays = [];
25
27
  this._sequenceRecordDeviceAttitudeMatrices = true;
28
+ this._sequenceRecorderFirstCameraToken = 0;
26
29
  this.onGLContextReset = new event_1.Event();
27
30
  }
28
31
  static create(client, mgr) {
@@ -43,6 +46,10 @@ class Pipeline {
43
46
  }, [msg]);
44
47
  }
45
48
  this.pendingMessages = [];
49
+ this.cleanOldFrames();
50
+ }
51
+ cleanOldFrames() {
52
+ var _a, _b;
46
53
  let currentToken = this._client.pipeline_camera_frame_user_data(this._impl);
47
54
  if (!currentToken)
48
55
  return;
@@ -50,12 +57,14 @@ class Pipeline {
50
57
  if (t[0] < currentToken) {
51
58
  if (t[1].texture)
52
59
  this.videoTextures.push(t[1].texture);
60
+ (_b = (_a = t[1].frame) === null || _a === void 0 ? void 0 : _a.close) === null || _b === void 0 ? void 0 : _b.call(_a);
53
61
  this.cameraTokens.delete(t[0]);
54
62
  }
55
63
  }
56
64
  }
57
65
  cameraTokenReturn(msg) {
58
- if (this._sequenceRecorder && this._sequenceRecordDeviceAttitudeMatrices) {
66
+ if (this._sequenceRecorder && this._sequenceRecordDeviceAttitudeMatrices
67
+ && msg.token >= this._sequenceRecorderFirstCameraToken) {
59
68
  let info = this.cameraTokens.get(msg.token);
60
69
  if (info) {
61
70
  if (msg.att)
@@ -71,6 +80,7 @@ class Pipeline {
71
80
  if (!this._sequenceRecorder)
72
81
  this._sequenceRecorder = new sequencerecorder_1.SequenceRecorder(expectedFrames);
73
82
  this._sequenceRecorder.start();
83
+ this._sequenceRecorderFirstCameraToken = this.nextCameraToken;
74
84
  }
75
85
  sequenceRecordStop() {
76
86
  var _a;
@@ -174,7 +184,7 @@ class Pipeline {
174
184
  let info = this.getCurrentCameraInfo();
175
185
  if (!info)
176
186
  return gl_matrix_1.mat4.create();
177
- return drawcamera_1.cameraFrameTextureMatrix(info.dataWidth, info.dataHeight, sw, sh, info.uvTransform, mirror);
187
+ return drawcamera_1.cameraFrameTextureMatrix(info.dataWidth, info.dataHeight, sw, sh, info.uvTransform || identity, mirror);
178
188
  }
179
189
  cameraFrameUserFacing() {
180
190
  var _a;
@@ -191,8 +201,48 @@ class Pipeline {
191
201
  gl_matrix_1.mat4.invert(res, res);
192
202
  return res;
193
203
  }
204
+ videoFrameFromWorker(msg) {
205
+ let tokenId = this.nextCameraToken++;
206
+ const cameraSource = camera_source_map_1.getCameraSource(msg.source);
207
+ if (!cameraSource)
208
+ return;
209
+ this.cameraTokens.set(tokenId, {
210
+ dataWidth: msg.w,
211
+ dataHeight: msg.h,
212
+ texture: undefined,
213
+ frame: msg.d,
214
+ userFacing: msg.userFacing,
215
+ uvTransform: msg.uvTransform,
216
+ cameraModel: msg.cameraModel,
217
+ cameraToDevice: msg.cameraToDevice,
218
+ cameraSource
219
+ });
220
+ this.cleanOldFrames();
221
+ }
222
+ imageBitmapFromWorker(msg) {
223
+ let data = this.cameraTokens.get(msg.tokenId);
224
+ if (!data)
225
+ return;
226
+ data.dataWidth = msg.dataWidth;
227
+ data.dataHeight = msg.dataHeight;
228
+ data.frame = msg.frame;
229
+ data.userFacing = msg.userFacing;
230
+ data.uvTransform = msg.uvTransform;
231
+ this.tokensInFlight--;
232
+ this.cleanOldFrames();
233
+ }
234
+ uploadGL() {
235
+ var _a, _b;
236
+ let info = this.getCurrentCameraInfo();
237
+ (_b = (_a = info === null || info === void 0 ? void 0 : info.cameraSource) === null || _a === void 0 ? void 0 : _a.uploadGL) === null || _b === void 0 ? void 0 : _b.call(_a, info);
238
+ }
239
+ registerToken(info) {
240
+ let tokenId = this.nextCameraToken++;
241
+ this.cameraTokens.set(tokenId, info);
242
+ this.tokensInFlight++;
243
+ return tokenId;
244
+ }
194
245
  processGL() {
195
- var _a;
196
246
  if (!this.glContext) {
197
247
  loglevel_1.zcerr("no GL context for camera frames - please call pipeline_gl_context_set");
198
248
  return;
@@ -203,26 +253,7 @@ class Pipeline {
203
253
  this.currentCameraSource.getFrame(true);
204
254
  return;
205
255
  }
206
- let info = this.currentCameraSource.getFrame(false);
207
- if (!info)
208
- return;
209
- let tokenId = this.nextCameraToken++;
210
- this.cameraTokens.set(tokenId, info);
211
- let msg = {
212
- d: info.data,
213
- p: this._impl,
214
- width: info.dataWidth,
215
- height: info.dataHeight,
216
- token: tokenId,
217
- userFacing: info.userFacing,
218
- c2d: info.cameraToDevice,
219
- cm: info.cameraModel,
220
- t: "cameraFrameC2S"
221
- };
222
- if (!this._sequenceRecordDeviceAttitudeMatrices)
223
- (_a = this._sequenceRecorder) === null || _a === void 0 ? void 0 : _a.appendCameraFrame(info);
224
- this.tokensInFlight++;
225
- this._mgr.postOutgoingMessage(msg, [info.data]);
256
+ this.currentCameraSource.getFrame(false);
226
257
  }
227
258
  motionAccelerometerSubmit(timestamp, x, y, z) {
228
259
  var _a;
@@ -246,9 +277,47 @@ class Pipeline {
246
277
  // This doesn't need to be added to the sequence since that's done on frame update instead
247
278
  this._client.pipeline_motion_attitude_matrix_submit(this._impl, m);
248
279
  }
249
- uploadGL() {
250
- let info = this.getCurrentCameraInfo();
251
- info === null || info === void 0 ? void 0 : info.cameraSource.uploadGL(info);
280
+ sendCameraStreamToWorker(source, stream, userFacing) {
281
+ let msg = {
282
+ t: "streamC2S",
283
+ p: this._impl,
284
+ s: stream,
285
+ userFacing,
286
+ source
287
+ };
288
+ this._mgr.postOutgoingMessage(msg, [msg.s]);
289
+ }
290
+ sendCameraToScreenRotationToWorker(rot) {
291
+ let msg = {
292
+ p: this._impl,
293
+ t: "cameraToScreenC2S",
294
+ r: rot
295
+ };
296
+ this._mgr.postOutgoingMessage(msg, []);
297
+ }
298
+ sendImageBitmapToWorker(img, rot, userFacing, tokenId, cameraModel, cameraToDevice) {
299
+ let msg = {
300
+ p: this._impl,
301
+ t: "imageBitmapC2S",
302
+ i: img,
303
+ r: rot,
304
+ tokenId,
305
+ userFacing,
306
+ cameraModel,
307
+ cameraToDevice
308
+ };
309
+ this._mgr.postOutgoingMessage(msg, [img]);
310
+ }
311
+ sendDataToWorker(data, token, width, height, userFacing, cameraToDevice, cameraModel) {
312
+ let msg = {
313
+ d: data,
314
+ p: this._impl,
315
+ width, height, token, userFacing,
316
+ c2d: cameraToDevice,
317
+ cm: cameraModel,
318
+ t: "cameraFrameC2S"
319
+ };
320
+ this._mgr.postOutgoingMessage(msg, [data]);
252
321
  }
253
322
  }
254
323
  exports.Pipeline = Pipeline;
package/lib/profile.d.ts CHANGED
@@ -13,4 +13,6 @@ export declare let profile: {
13
13
  dataWidth: number;
14
14
  dataHeight: number;
15
15
  videoElementInDOM: boolean;
16
+ preferMediaStreamTrackProcessorCamera: boolean;
17
+ preferImageBitmapCamera: boolean;
16
18
  };
package/lib/profile.js CHANGED
@@ -17,56 +17,67 @@ exports.profile = {
17
17
  videoHeight: 480,
18
18
  dataWidth: 320,
19
19
  dataHeight: 240,
20
- videoElementInDOM: false
20
+ videoElementInDOM: false,
21
+ preferMediaStreamTrackProcessorCamera: false,
22
+ preferImageBitmapCamera: false
21
23
  };
22
- window["zeeProfile"] = exports.profile;
24
+ if (typeof window !== "undefined") {
25
+ window["zeeProfile"] = exports.profile;
26
+ if (window.location.href.indexOf("_mstppipeline") >= 0) {
27
+ console.log("Configuring for MSTP camera pipeline (if supported)");
28
+ exports.profile.preferMediaStreamTrackProcessorCamera = true;
29
+ }
30
+ if (window.location.href.indexOf("_imagebitmappipeline") >= 0) {
31
+ console.log("Configuring for ImageBitmap camera pipeline (if supported)");
32
+ exports.profile.preferImageBitmapCamera = true;
33
+ }
34
+ }
23
35
  let agent = new UAParser.UAParser();
24
- switch (agent.getBrowser().name) {
25
- case "Safari":
26
- exports.profile.deviceMotionMutliplier = 1.0;
27
- if (window.orientation === undefined) {
28
- // Desktop Safari
29
- break;
30
- }
31
- exports.profile.videoElementInDOM = true;
32
- exports.profile.showSafariPermissionsResetIfNecessary = true;
33
- break;
34
- case "Chrome":
35
- let engine = agent.getEngine();
36
- if (!engine || engine.name !== "WebKit") {
37
- break;
38
- }
39
- case "Mobile Safari":
40
- exports.profile.deviceMotionMutliplier = 1.0;
41
- let version = agent.getOS().version;
42
- if (version) {
43
- let versionParts = version.split(".");
44
- if (versionParts.length >= 2) {
45
- const majorVersion = parseInt(versionParts[0]);
46
- const minorVersion = parseInt(versionParts[1]);
47
- if (majorVersion < 11 ||
48
- (majorVersion === 11 && minorVersion < 3)) {
49
- exports.profile.blacklisted = true;
50
- }
51
- if (majorVersion < 12 ||
52
- (majorVersion === 12 && minorVersion < 2)) {
53
- exports.profile.videoElementInDOM = true;
54
- }
55
- if ((majorVersion === 12 && minorVersion >= 2) || (majorVersion >= 13))
56
- exports.profile.showGyroPermissionsWarningIfNecessary = true;
57
- if (majorVersion >= 13) {
58
- exports.profile.showSafariPermissionsResetIfNecessary = true;
59
- }
60
- if (((majorVersion >= 12 && minorVersion > 1) || (majorVersion >= 13)) &&
61
- navigator.mediaDevices &&
62
- navigator.mediaDevices.getSupportedConstraints &&
63
- navigator.mediaDevices.getSupportedConstraints().frameRate) {
64
- exports.profile.requestHighFrameRate = true;
36
+ let os = (agent.getOS().name || "unknown").toLowerCase();
37
+ let engine = (agent.getEngine().name || "unknown").toLowerCase();
38
+ if (engine === "webkit" && os !== "ios") {
39
+ exports.profile.deviceMotionMutliplier = 1.0;
40
+ if (typeof window !== "undefined" && window.orientation !== undefined) {
41
+ // iPad
42
+ iDevice();
43
+ }
44
+ }
45
+ if (engine === "webkit" && os === "ios") {
46
+ exports.profile.deviceMotionMutliplier = 1.0;
47
+ iDevice();
48
+ }
49
+ function iDevice() {
50
+ let version = agent.getOS().version;
51
+ if (version) {
52
+ let versionParts = version.split(".");
53
+ if (versionParts.length >= 2) {
54
+ const majorVersion = parseInt(versionParts[0]);
55
+ const minorVersion = parseInt(versionParts[1]);
56
+ if (majorVersion < 11 ||
57
+ (majorVersion === 11 && minorVersion < 3)) {
58
+ exports.profile.blacklisted = true;
59
+ }
60
+ if (majorVersion < 12 ||
61
+ (majorVersion === 12 && minorVersion < 2)) {
62
+ exports.profile.videoElementInDOM = true;
63
+ }
64
+ if ((majorVersion === 12 && minorVersion >= 2) || (majorVersion >= 13))
65
+ exports.profile.showGyroPermissionsWarningIfNecessary = true;
66
+ if (majorVersion >= 13) {
67
+ exports.profile.showSafariPermissionsResetIfNecessary = true;
68
+ }
69
+ if (((majorVersion >= 12 && minorVersion > 1) || (majorVersion >= 13)) &&
70
+ navigator.mediaDevices &&
71
+ navigator.mediaDevices.getSupportedConstraints &&
72
+ navigator.mediaDevices.getSupportedConstraints().frameRate) {
73
+ exports.profile.requestHighFrameRate = true;
74
+ if (majorVersion < 14) {
65
75
  // Avoid bug where iOS letterboxes 16:9 into 4:3 for high fps
76
+ // Doesn't seem needed with newer versions of iOS, tested on 14.8.1 and 15.2
66
77
  exports.profile.videoHeight = 360;
67
78
  exports.profile.dataHeight = 180;
68
79
  }
69
80
  }
70
81
  }
71
- break;
82
+ }
72
83
  }
@@ -0,0 +1,18 @@
1
+ export interface Chunk {
2
+ ident: string;
3
+ data: Uint8Array;
4
+ subident?: string;
5
+ subchunks?: Chunk[];
6
+ }
7
+ export declare class RiffReader {
8
+ private _data;
9
+ private _paddingBytes;
10
+ truncatedChunks: boolean;
11
+ private _view;
12
+ root: Chunk;
13
+ constructor(_data: ArrayBuffer, _paddingBytes?: boolean);
14
+ private _parse;
15
+ private _parseChunk;
16
+ find(str: string, inChunk?: Chunk): Chunk | undefined;
17
+ has(str: string): boolean;
18
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RiffReader = void 0;
4
+ const decoder = new TextDecoder();
5
+ class RiffReader {
6
+ constructor(_data, _paddingBytes = false) {
7
+ this._data = _data;
8
+ this._paddingBytes = _paddingBytes;
9
+ this.truncatedChunks = false;
10
+ this._view = new DataView(this._data);
11
+ this.root = this._parse();
12
+ }
13
+ _parse() {
14
+ const header = decoder.decode(this._data.slice(0, 4));
15
+ if (header !== "RIFF")
16
+ throw new Error("Not a valid ZPT file");
17
+ return this._parseChunk(0);
18
+ }
19
+ _parseChunk(offset) {
20
+ const ident = decoder.decode(this._data.slice(offset, offset + 4));
21
+ const length = this._view.getUint32(offset + 4, true);
22
+ const data = new Uint8Array(this._data, offset + 8, length);
23
+ if (data.byteLength !== length)
24
+ this.truncatedChunks = true;
25
+ let subchunks;
26
+ let subident;
27
+ if (ident === "RIFF" || ident === "LIST") {
28
+ subident = decoder.decode(this._data.slice(offset + 8, offset + 12));
29
+ subchunks = [];
30
+ let currentOffset = 4;
31
+ while (currentOffset < data.byteLength - 1) {
32
+ const subchunk = this._parseChunk(offset + 8 + currentOffset);
33
+ subchunks.push(subchunk);
34
+ currentOffset += subchunk.data.byteLength + 8;
35
+ if (this._paddingBytes && subchunk.data.byteLength & 0x1)
36
+ currentOffset++;
37
+ }
38
+ }
39
+ return { ident, data, subident, subchunks };
40
+ }
41
+ find(str, inChunk = this.root) {
42
+ if (inChunk.ident === str)
43
+ return inChunk;
44
+ if (!inChunk.subchunks)
45
+ return;
46
+ for (let c of inChunk.subchunks) {
47
+ const found = this.find(str, c);
48
+ if (found)
49
+ return found;
50
+ }
51
+ }
52
+ has(str) {
53
+ return this.find(str) !== undefined;
54
+ }
55
+ }
56
+ exports.RiffReader = RiffReader;
@@ -26,6 +26,7 @@ export declare class SequenceRecorder {
26
26
  private _insertionByte;
27
27
  private _numberPackets;
28
28
  private _started;
29
+ private _hasLoggedUnsuppored;
29
30
  constructor(estimatedFrames: number);
30
31
  private _estimatedSize;
31
32
  start(): void;
@@ -15,6 +15,7 @@ class SequenceRecorder {
15
15
  this._insertionByte = 0;
16
16
  this._numberPackets = 0;
17
17
  this._started = false;
18
+ this._hasLoggedUnsuppored = false;
18
19
  this._data = new ArrayBuffer(this._estimatedSize(estimatedFrames, 320, 240));
19
20
  this._dataView = new DataView(this._data);
20
21
  this._dataUint8 = new Uint8Array(this._data);
@@ -38,6 +39,9 @@ class SequenceRecorder {
38
39
  this._started = false;
39
40
  let trimmed = this._data.slice(0, this._insertionByte);
40
41
  this._data = trimmed;
42
+ this._dataUint8 = new Uint8Array(this._data);
43
+ this._dataFloat32 = new Float32Array(this._data);
44
+ this._dataView = new DataView(this._data);
41
45
  }
42
46
  data() {
43
47
  return this._dataUint8;
@@ -45,6 +49,13 @@ class SequenceRecorder {
45
49
  appendCameraFrame(c) {
46
50
  if (!this._started)
47
51
  return;
52
+ if (!c.data) {
53
+ if (this._hasLoggedUnsuppored)
54
+ return;
55
+ this._hasLoggedUnsuppored = true;
56
+ loglevel_1.zcerr("Unable to record frames from this camera source");
57
+ return;
58
+ }
48
59
  if (c.data.byteLength !== (c.dataWidth * c.dataHeight)) {
49
60
  loglevel_1.zcerr("Unable to record frame to sequence: greyscale array doesn't match dimensions");
50
61
  return;
@@ -4,14 +4,20 @@ export declare class SequenceSource extends Source {
4
4
  private _impl;
5
5
  private _pipeline;
6
6
  private _packetNumber;
7
+ private _motionUpdatesQueued;
8
+ private _motionUpdatesSent;
7
9
  private _decoder;
10
+ private _minFrameGapMs;
11
+ private _lastUpdateTime;
8
12
  static create(p: zappar_pipeline_t): zappar_sequence_source_t;
9
13
  static get(m: zappar_sequence_source_t): SequenceSource | undefined;
10
14
  constructor(_impl: zappar_sequence_source_t, _pipeline: zappar_pipeline_t);
11
15
  loadFromMemory(data: ArrayBuffer): void;
12
- getFrame(currentlyProcessing: boolean): CameraFrameInfo | undefined;
16
+ maxPlaybackFpsSet(fps: number): void;
17
+ getFrame(currentlyProcessing: boolean): void;
13
18
  destroy(): void;
14
19
  start(): void;
15
20
  pause(): void;
16
21
  uploadGL(info: CameraFrameInfo): void;
22
+ private _submitMotionUpdates;
17
23
  }
@@ -14,6 +14,10 @@ class SequenceSource extends source_1.Source {
14
14
  this._impl = _impl;
15
15
  this._pipeline = _pipeline;
16
16
  this._packetNumber = 0;
17
+ this._motionUpdatesQueued = 0;
18
+ this._motionUpdatesSent = 0;
19
+ this._minFrameGapMs = 0;
20
+ this._lastUpdateTime = 0;
17
21
  }
18
22
  static create(p) {
19
23
  let ret = (latest++);
@@ -28,66 +32,68 @@ class SequenceSource extends source_1.Source {
28
32
  try {
29
33
  this._decoder = new sequencerecorder_1.SequenceDecoder(data);
30
34
  this._packetNumber = 0;
35
+ this._lastUpdateTime = 0;
31
36
  }
32
37
  catch (err) {
33
38
  loglevel_1.zcerr("Unable to decode sequence:", err);
34
39
  }
35
40
  }
41
+ maxPlaybackFpsSet(fps) {
42
+ if (fps <= 0) {
43
+ this._minFrameGapMs = 0;
44
+ return;
45
+ }
46
+ this._minFrameGapMs = 1000.0 / fps;
47
+ }
36
48
  getFrame(currentlyProcessing) {
37
49
  let pipeline = pipeline_1.Pipeline.get(this._pipeline);
38
50
  if (!pipeline)
39
51
  return;
52
+ if (!this._decoder)
53
+ return;
54
+ this._submitMotionUpdates(pipeline);
55
+ if (this._motionUpdatesQueued > this._motionUpdatesSent)
56
+ return;
40
57
  if (currentlyProcessing)
41
58
  return;
42
- if (!this._decoder)
59
+ let curTime = performance.now();
60
+ if (curTime < this._lastUpdateTime + this._minFrameGapMs)
43
61
  return;
44
- while (this._packetNumber < this._decoder.numberPackets) {
45
- let packet = this._decoder.dataByPacket.get(this._packetNumber);
46
- this._packetNumber++;
47
- if (!packet)
48
- return;
49
- switch (packet.type) {
50
- case sequencerecorder_1.SequenceRecorderPacketType.ACCELEROMETER:
51
- pipeline.motionAccelerometerSubmit(packet.t, packet.x, packet.y, packet.z);
52
- break;
53
- case sequencerecorder_1.SequenceRecorderPacketType.ROTATION_RATE:
54
- pipeline.motionRotationRateSubmit(packet.t, packet.x, packet.y, packet.z);
55
- break;
56
- case sequencerecorder_1.SequenceRecorderPacketType.ATTITUDE:
57
- pipeline.motionAttitudeSubmit(packet.t, packet.x, packet.y, packet.z);
58
- break;
59
- case sequencerecorder_1.SequenceRecorderPacketType.ATTITUDE_MATRIX:
60
- pipeline.motionAttitudeMatrix(packet.attitude);
61
- break;
62
- case sequencerecorder_1.SequenceRecorderPacketType.CAMERA_FRAME:
63
- {
64
- let pixels = pipeline.cameraPixelArrays.pop();
65
- while (pixels) {
66
- if (pixels.byteLength === packet.greyscale.byteLength)
67
- break;
68
- pixels = pipeline.cameraPixelArrays.pop();
69
- }
70
- if (!pixels) {
71
- pixels = new ArrayBuffer(packet.greyscale.byteLength);
72
- }
73
- (new Uint8Array(pixels)).set(packet.greyscale);
74
- return {
75
- data: pixels,
76
- cameraSourceData: packet.greyscale,
77
- cameraModel: packet.cameraModel,
78
- cameraToDevice: packet.cameraToDevice,
79
- dataWidth: packet.width,
80
- dataHeight: packet.height,
81
- texture: undefined,
82
- userFacing: packet.userFacing,
83
- uvTransform: gl_matrix_1.mat4.create(),
84
- cameraSource: this
85
- };
86
- break;
87
- }
88
- }
62
+ if (this._packetNumber >= this._decoder.numberPackets)
63
+ return;
64
+ let packet = this._decoder.dataByPacket.get(this._packetNumber);
65
+ if (packet.type != sequencerecorder_1.SequenceRecorderPacketType.CAMERA_FRAME)
66
+ return;
67
+ this._packetNumber++;
68
+ let pixels = pipeline.cameraPixelArrays.pop();
69
+ while (pixels) {
70
+ if (pixels.byteLength === packet.greyscale.byteLength)
71
+ break;
72
+ pixels = pipeline.cameraPixelArrays.pop();
73
+ }
74
+ if (!pixels) {
75
+ pixels = new ArrayBuffer(packet.greyscale.byteLength);
89
76
  }
90
- return undefined;
77
+ (new Uint8Array(pixels)).set(packet.greyscale);
78
+ this._lastUpdateTime = curTime;
79
+ let info = {
80
+ data: pixels,
81
+ cameraSourceData: packet.greyscale,
82
+ cameraModel: packet.cameraModel,
83
+ cameraToDevice: packet.cameraToDevice,
84
+ dataWidth: packet.width,
85
+ dataHeight: packet.height,
86
+ texture: undefined,
87
+ userFacing: packet.userFacing,
88
+ uvTransform: gl_matrix_1.mat4.create(),
89
+ cameraSource: this
90
+ };
91
+ // We can queue the motion updates for the follwing frame immediately
92
+ // as this camera frame will be sent immediately, but the next motion
93
+ // updates will be one frame later
94
+ this._submitMotionUpdates(pipeline);
95
+ const token = pipeline.registerToken(info);
96
+ pipeline.sendDataToWorker(info.data || new ArrayBuffer(0), token, info.dataWidth, info.dataHeight, info.userFacing, info.cameraToDevice, info.cameraModel);
91
97
  }
92
98
  destroy() {
93
99
  byId.delete(this._impl);
@@ -124,5 +130,41 @@ class SequenceSource extends source_1.Source {
124
130
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, info.dataWidth, info.dataHeight, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, new Uint8Array(info.cameraSourceData));
125
131
  gl.bindTexture(gl.TEXTURE_2D, null);
126
132
  }
133
+ _submitMotionUpdates(pipeline) {
134
+ let pendingMotionUpdate = false;
135
+ while (this._packetNumber < this._decoder.numberPackets) {
136
+ let packet = this._decoder.dataByPacket.get(this._packetNumber);
137
+ if (packet.type == sequencerecorder_1.SequenceRecorderPacketType.CAMERA_FRAME)
138
+ break;
139
+ switch (packet.type) {
140
+ case sequencerecorder_1.SequenceRecorderPacketType.ACCELEROMETER:
141
+ pipeline.motionAccelerometerSubmit(packet.t, packet.x, packet.y, packet.z);
142
+ pendingMotionUpdate = true;
143
+ break;
144
+ case sequencerecorder_1.SequenceRecorderPacketType.ROTATION_RATE:
145
+ pipeline.motionRotationRateSubmit(packet.t, packet.x, packet.y, packet.z);
146
+ pendingMotionUpdate = true;
147
+ break;
148
+ case sequencerecorder_1.SequenceRecorderPacketType.ATTITUDE:
149
+ pipeline.motionAttitudeSubmit(packet.t, packet.x, packet.y, packet.z);
150
+ pendingMotionUpdate = true;
151
+ break;
152
+ case sequencerecorder_1.SequenceRecorderPacketType.ATTITUDE_MATRIX:
153
+ pipeline.motionAttitudeMatrix(packet.attitude);
154
+ pendingMotionUpdate = true;
155
+ break;
156
+ }
157
+ this._packetNumber++;
158
+ }
159
+ // If we've submitted motion updates, add a setTimeout to reflect when
160
+ // the message serializer will actually have sent them over to the worker
161
+ if (pendingMotionUpdate) {
162
+ this._motionUpdatesQueued++;
163
+ setTimeout(() => {
164
+ this._motionUpdatesSent++;
165
+ }, 0);
166
+ }
167
+ return;
168
+ }
127
169
  }
128
170
  exports.SequenceSource = SequenceSource;
package/lib/source.d.ts CHANGED
@@ -1,17 +1,19 @@
1
+ /// <reference types="dom-webcodecs" />
1
2
  export interface CameraFrameInfo {
2
- data: ArrayBuffer;
3
+ data?: ArrayBuffer;
3
4
  texture: WebGLTexture | undefined;
4
5
  dataWidth: number;
5
6
  dataHeight: number;
6
7
  cameraModel: Float32Array;
7
8
  cameraToDevice: Float32Array;
8
- uvTransform: Float32Array;
9
- userFacing: boolean;
10
9
  cameraSource: Source;
11
10
  cameraSourceData?: any;
11
+ uvTransform?: Float32Array;
12
+ userFacing: boolean;
13
+ frame?: VideoFrame | ImageBitmap;
12
14
  }
13
15
  export declare abstract class Source {
14
- abstract getFrame(currentlyProcessing: boolean): CameraFrameInfo | undefined;
16
+ abstract getFrame(currentlyProcessing: boolean): void;
15
17
  abstract pause(): void;
16
18
  abstract uploadGL(info: CameraFrameInfo): void;
17
19
  }
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.4.0-beta.1";
1
+ export declare const VERSION = "0.4.0-beta.10";
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = "0.4.0-beta.1";
4
+ exports.VERSION = "0.4.0-beta.10";
@@ -10,7 +10,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.launchWorker = exports.messageManager = void 0;
13
- const bundleworker_mainthread_1 = require("./bundleworker-mainthread");
14
13
  const messages_1 = require("./messages");
15
14
  exports.messageManager = new messages_1.MsgManager();
16
15
  let Worker;
@@ -29,10 +28,6 @@ function launchWorker() {
29
28
  t: "wasm",
30
29
  url: require("./zcv.wasm").default
31
30
  });
32
- worker.postMessage({
33
- t: "port",
34
- port: bundleworker_mainthread_1.bundleWorkerMessageChannel.port1
35
- }, [bundleworker_mainthread_1.bundleWorkerMessageChannel.port1]);
36
31
  yield waitForLoad(worker);
37
32
  function sendOutgoing() {
38
33
  let msgs = exports.messageManager.getOutgoingMessages();