@zappar/zappar-cv 0.4.0-beta.3 → 0.4.0-beta.9

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 (60) hide show
  1. package/CHANGELOG.md +79 -34
  2. package/README.md +2 -2
  3. package/lib/camera-source-map.d.ts +10 -0
  4. package/lib/camera-source-map.js +40 -0
  5. package/lib/camera-source.d.ts +2 -5
  6. package/lib/camera-source.js +3 -13
  7. package/lib/compatibility.js +1 -1
  8. package/lib/drawcamera.js +2 -1
  9. package/lib/gen/zappar-client.js +6 -1
  10. package/lib/gen/zappar-cwrap.js +37 -21
  11. package/lib/gen/zappar-native.d.ts +11 -0
  12. package/lib/gen/zappar-native.js +13 -1
  13. package/lib/gen/zappar-server.js +1 -1
  14. package/lib/gen/zappar.d.ts +5 -0
  15. package/lib/gen/zappar.js +5 -3
  16. package/lib/gfx.d.ts +1 -0
  17. package/lib/gfx.js +4 -0
  18. package/lib/gl-state-manager.d.ts +9 -0
  19. package/lib/gl-state-manager.js +35 -0
  20. package/lib/html-element-source.d.ts +3 -20
  21. package/lib/html-element-source.js +19 -263
  22. package/lib/image-process-gl.d.ts +37 -0
  23. package/lib/image-process-gl.js +298 -0
  24. package/lib/imagebitmap-camera-source.d.ts +36 -0
  25. package/lib/imagebitmap-camera-source.js +277 -0
  26. package/lib/mstp-camera-source.d.ts +29 -0
  27. package/lib/mstp-camera-source.js +230 -0
  28. package/lib/native.js +45 -8
  29. package/lib/pipeline.d.ts +13 -3
  30. package/lib/pipeline.js +95 -26
  31. package/lib/profile.d.ts +2 -0
  32. package/lib/profile.js +55 -44
  33. package/lib/sequencerecorder.d.ts +1 -0
  34. package/lib/sequencerecorder.js +11 -0
  35. package/lib/sequencesource.d.ts +7 -1
  36. package/lib/sequencesource.js +89 -47
  37. package/lib/source.d.ts +6 -4
  38. package/lib/version.d.ts +1 -1
  39. package/lib/version.js +1 -1
  40. package/lib/worker-client.js +0 -5
  41. package/lib/worker-imagebitmap.d.ts +5 -0
  42. package/lib/worker-imagebitmap.js +63 -0
  43. package/lib/worker-server.d.ts +0 -5
  44. package/lib/worker-server.js +120 -24
  45. package/lib/workerinterface.d.ts +47 -1
  46. package/lib/zcv.js +117 -135
  47. package/lib/zcv.wasm +0 -0
  48. package/package.json +34 -31
  49. package/umd/a78f5ad0a44def457ee50c8bcd5fd27c.wasm +0 -0
  50. package/umd/zappar-cv.js +1 -9
  51. package/umd/zappar-cv.worker.js +1 -1
  52. package/lib/SLAM_Worker.js +0 -16
  53. package/lib/SLAM_Worker.wasm +0 -0
  54. package/lib/bundleworker-mainthread.d.ts +0 -2
  55. package/lib/bundleworker-mainthread.js +0 -36
  56. package/lib/bundleworker-worker.d.ts +0 -6
  57. package/lib/bundleworker-worker.js +0 -34
  58. package/umd/1ec038c18c27f4adf35917a8175401f0.wasm +0 -0
  59. package/umd/427496550eba276b65c7.bundleworker.js +0 -1
  60. package/umd/d115e485cffe500afc4f7c1272ea8f62.wasm +0 -0
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
  }
@@ -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.3";
1
+ export declare const VERSION = "0.4.0-beta.9";
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.3";
4
+ exports.VERSION = "0.4.0-beta.9";
@@ -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();
@@ -0,0 +1,5 @@
1
+ import { zappar_cwrap } from "./gen/zappar-native";
2
+ import { zappar_server } from "./gen/zappar-server";
3
+ import { MsgManager } from "./messages";
4
+ import { ImageBitmapC2S } from "./workerinterface";
5
+ export declare function handleImageBitmap(m: ImageBitmapC2S, r: zappar_cwrap, server: zappar_server, mgr: MsgManager): void;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleImageBitmap = void 0;
4
+ const image_process_gl_1 = require("./image-process-gl");
5
+ const profile_1 = require("./profile");
6
+ const gl_matrix_1 = require("gl-matrix");
7
+ let pixels;
8
+ let texture;
9
+ let _imageProcessor;
10
+ let _gl;
11
+ function getImageProcessor() {
12
+ if (!_imageProcessor || !_gl) {
13
+ const canvas = new OffscreenCanvas(1, 1);
14
+ _gl = canvas.getContext("webgl");
15
+ if (!_gl)
16
+ throw new Error("Unable to get offscreen GL context");
17
+ _imageProcessor = new image_process_gl_1.ImageProcessGL(_gl);
18
+ }
19
+ return [_imageProcessor, _gl];
20
+ }
21
+ function handleImageBitmap(m, r, server, mgr) {
22
+ // img: ImageBitmap,
23
+ // rot: number,
24
+ // tokenId: number,
25
+ // r: zappar_cwrap,
26
+ // p: zappar_pipeline_t,
27
+ // userFacing: boolean,
28
+ // server: zappar_server,
29
+ // mgr: MsgManager) {
30
+ const [imageProcessor, gl] = getImageProcessor();
31
+ if (!texture) {
32
+ texture = gl.createTexture();
33
+ gl.bindTexture(gl.TEXTURE_2D, texture);
34
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
35
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
36
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
37
+ }
38
+ if (!texture)
39
+ return;
40
+ if (!pixels || pixels.byteLength < profile_1.profile.dataWidth * profile_1.profile.dataHeight) {
41
+ console.log("Generating pixel buffer", profile_1.profile.dataWidth * profile_1.profile.dataHeight);
42
+ pixels = new ArrayBuffer(profile_1.profile.dataWidth * profile_1.profile.dataHeight);
43
+ }
44
+ imageProcessor.uploadFrame(texture, m.i, m.r, m.userFacing);
45
+ let info = imageProcessor.readFrame(texture, pixels);
46
+ let msg = {
47
+ t: "imageBitmapS2C",
48
+ dataWidth: info.dataWidth,
49
+ dataHeight: info.dataHeight,
50
+ frame: m.i,
51
+ userFacing: info.userFacing,
52
+ uvTransform: info.uvTransform || gl_matrix_1.mat4.create(),
53
+ tokenId: m.tokenId, p: m.p
54
+ };
55
+ mgr.postOutgoingMessage(msg, [m.i]);
56
+ let pipeline = server._pipeline_by_instance.get(m.p);
57
+ if (pipeline) {
58
+ r.pipeline_camera_frame_submit(pipeline, pixels, info.dataWidth, info.dataHeight, m.tokenId, m.cameraToDevice, m.cameraModel, info.userFacing);
59
+ r.pipeline_frame_update(pipeline);
60
+ server.exploreState();
61
+ }
62
+ }
63
+ exports.handleImageBitmap = handleImageBitmap;
@@ -1,8 +1,3 @@
1
1
  import { MsgManager } from "./messages";
2
2
  export declare let messageManager: MsgManager;
3
- declare global {
4
- interface Window {
5
- bundle_adjust_message: any;
6
- }
7
- }
8
3
  export declare function launchWorkerServer(wasmUrl: string): Promise<void>;
@@ -14,21 +14,12 @@ const ZNM = require("./zcv");
14
14
  const zappar_cwrap_1 = require("./gen/zappar-cwrap");
15
15
  const zappar_server_1 = require("./gen/zappar-server");
16
16
  const messages_1 = require("./messages");
17
+ const gl_matrix_1 = require("gl-matrix");
18
+ const zappar_native_1 = require("./gen/zappar-native");
19
+ const worker_imagebitmap_1 = require("./worker-imagebitmap");
20
+ const profile_1 = require("./profile");
17
21
  exports.messageManager = new messages_1.MsgManager();
18
- let bundleWorkerPort;
19
- self.addEventListener("message", msg => {
20
- if (msg && msg.data && msg.data.t === "port") {
21
- bundleWorkerPort = msg.data.port;
22
- }
23
- });
24
- self.bundle_adjust_message = function (buf) {
25
- var buf_copy = new ArrayBuffer(buf.byteLength);
26
- new Uint8Array(buf_copy).set(new Uint8Array(buf));
27
- bundleWorkerPort === null || bundleWorkerPort === void 0 ? void 0 : bundleWorkerPort.postMessage({
28
- t: "bundle_adjust_message",
29
- buf: buf_copy
30
- }, [buf_copy]);
31
- };
22
+ let latestCameraToScreenRotation = 0;
32
23
  function launchWorkerServer(wasmUrl) {
33
24
  return __awaiter(this, void 0, void 0, function* () {
34
25
  let mod = ZNM.default({
@@ -48,15 +39,6 @@ function launchWorkerServer(wasmUrl) {
48
39
  }, [ab]);
49
40
  });
50
41
  exports.messageManager.postOutgoingMessage("loaded", []);
51
- bundleWorkerPort.onmessage = function (msg) {
52
- // Received message from other worker
53
- var a_buf = msg.data.buf;
54
- var buf = mod._malloc(a_buf.byteLength);
55
- mod.HEAPU8.set(new Uint8Array(a_buf), buf);
56
- /// call the exported native function to update the world map
57
- mod._bundle_adjust_message_callback(buf, msg.data.buf.byteLength, 0);
58
- mod._free(buf);
59
- };
60
42
  exports.messageManager.onIncomingMessage.bind((msg) => {
61
43
  var _a;
62
44
  switch (msg.t) {
@@ -67,7 +49,7 @@ function launchWorkerServer(wasmUrl) {
67
49
  case "buf":
68
50
  (_a = server.serializersByPipelineId.get(msg.p)) === null || _a === void 0 ? void 0 : _a.bufferReturn(msg.d);
69
51
  break;
70
- case "cameraFrameC2S":
52
+ case "cameraFrameC2S": {
71
53
  let msgt = msg;
72
54
  let pipeline = server._pipeline_by_instance.get(msgt.p);
73
55
  let att;
@@ -86,6 +68,22 @@ function launchWorkerServer(wasmUrl) {
86
68
  };
87
69
  exports.messageManager.postOutgoingMessage(ret, [msgt.d]);
88
70
  break;
71
+ }
72
+ case "streamC2S": {
73
+ let msgt = msg;
74
+ consumeStream(mod, r, msgt.s, msgt.p, msgt.userFacing, server, msgt.source);
75
+ break;
76
+ }
77
+ case "cameraToScreenC2S": {
78
+ let msgt = msg;
79
+ latestCameraToScreenRotation = msgt.r;
80
+ break;
81
+ }
82
+ case "imageBitmapC2S": {
83
+ let msgt = msg;
84
+ worker_imagebitmap_1.handleImageBitmap(msgt, r, server, exports.messageManager);
85
+ break;
86
+ }
89
87
  }
90
88
  });
91
89
  }
@@ -94,3 +92,101 @@ function launchWorkerServer(wasmUrl) {
94
92
  }
95
93
  exports.launchWorkerServer = launchWorkerServer;
96
94
  ;
95
+ let streamDataBufferPointer = 0;
96
+ let streamDataBufferLength = 0;
97
+ let tokenId = 1;
98
+ const cameraToDeviceTransform = gl_matrix_1.mat4.create();
99
+ const cameraModel = new Float32Array([300, 300, 160, 120, 0, 0]);
100
+ function consumeStream(mod, r, stream, p, userFacing, server, source) {
101
+ return __awaiter(this, void 0, void 0, function* () {
102
+ const reader = yield stream.getReader();
103
+ while (true) {
104
+ let result = yield reader.read();
105
+ if (result.done) {
106
+ console.log("Stream done");
107
+ return;
108
+ }
109
+ let frame = result.value;
110
+ let size = frame.allocationSize();
111
+ if (size > streamDataBufferLength) {
112
+ if (streamDataBufferPointer > 0)
113
+ mod._free(streamDataBufferPointer);
114
+ streamDataBufferPointer = mod._malloc(size);
115
+ streamDataBufferLength = size;
116
+ }
117
+ yield frame.copyTo(mod.HEAPU8.subarray(streamDataBufferPointer, streamDataBufferPointer + streamDataBufferLength));
118
+ let token = tokenId;
119
+ tokenId++;
120
+ const width = frame.visibleRect.width;
121
+ const height = frame.visibleRect.height;
122
+ let uvTransform;
123
+ let dataWidth = width;
124
+ let dataHeight = height;
125
+ switch (latestCameraToScreenRotation) {
126
+ case 270:
127
+ uvTransform = new Float32Array([0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1]);
128
+ dataWidth = height;
129
+ dataHeight = width;
130
+ break;
131
+ case 180:
132
+ uvTransform = new Float32Array([-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1]);
133
+ break;
134
+ case 90:
135
+ uvTransform = new Float32Array([0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1]);
136
+ dataWidth = height;
137
+ dataHeight = width;
138
+ break;
139
+ default:
140
+ uvTransform = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
141
+ break;
142
+ }
143
+ let clone = frame.clone();
144
+ if (userFacing)
145
+ gl_matrix_1.mat4.fromScaling(cameraToDeviceTransform, [-1, 1, -1]);
146
+ else
147
+ gl_matrix_1.mat4.identity(cameraToDeviceTransform);
148
+ let focalLength = 300.0 * profile_1.profile.dataWidth / 320.0;
149
+ cameraModel[0] = focalLength;
150
+ cameraModel[1] = focalLength;
151
+ cameraModel[2] = profile_1.profile.dataWidth * 0.5;
152
+ cameraModel[3] = profile_1.profile.dataHeight * 0.5;
153
+ const ret = {
154
+ token: token,
155
+ d: clone,
156
+ p: p,
157
+ t: "videoFrameS2C",
158
+ userFacing,
159
+ uvTransform,
160
+ w: dataWidth,
161
+ h: dataHeight,
162
+ cameraToDevice: cameraToDeviceTransform,
163
+ cameraModel,
164
+ source
165
+ };
166
+ exports.messageManager.postOutgoingMessage(ret, [ret.d, ret.uvTransform.buffer]);
167
+ const pipeline = server._pipeline_by_instance.get(p);
168
+ if (pipeline) {
169
+ r.pipeline_camera_frame_submit_raw_pointer(pipeline, streamDataBufferPointer, size, framePixelFormatFromFormat(frame.format), width, height, token, cameraToDeviceTransform, latestCameraToScreenRotation, cameraModel, userFacing);
170
+ r.pipeline_frame_update(pipeline);
171
+ server.exploreState();
172
+ }
173
+ frame.close();
174
+ }
175
+ });
176
+ }
177
+ function framePixelFormatFromFormat(f) {
178
+ switch (f) {
179
+ case "I420": return zappar_native_1.frame_pixel_format_t.FRAME_PIXEL_FORMAT_I420;
180
+ case "I420A": return zappar_native_1.frame_pixel_format_t.FRAME_PIXEL_FORMAT_I420A;
181
+ case "I422": return zappar_native_1.frame_pixel_format_t.FRAME_PIXEL_FORMAT_I422;
182
+ case "I444": return zappar_native_1.frame_pixel_format_t.FRAME_PIXEL_FORMAT_I444;
183
+ case "NV12": return zappar_native_1.frame_pixel_format_t.FRAME_PIXEL_FORMAT_NV12;
184
+ case "RGBA":
185
+ case "RGBX":
186
+ return zappar_native_1.frame_pixel_format_t.FRAME_PIXEL_FORMAT_RGBA;
187
+ case "BGRA":
188
+ case "BGRX":
189
+ return zappar_native_1.frame_pixel_format_t.FRAME_PIXEL_FORMAT_BGRA;
190
+ }
191
+ return zappar_native_1.frame_pixel_format_t.FRAME_PIXEL_FORMAT_Y;
192
+ }