@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.
- package/CHANGELOG.md +79 -34
- package/README.md +2 -2
- package/lib/additional.d.ts +2 -1
- package/lib/camera-source-map.d.ts +10 -0
- package/lib/camera-source-map.js +40 -0
- package/lib/camera-source.d.ts +2 -5
- package/lib/camera-source.js +3 -13
- package/lib/compatibility.js +1 -1
- package/lib/drawcamera.js +2 -1
- package/lib/gen/zappar-client.js +6 -16
- package/lib/gen/zappar-cwrap.js +37 -28
- package/lib/gen/zappar-native.d.ts +11 -1
- package/lib/gen/zappar-native.js +13 -1
- package/lib/gen/zappar-server.js +1 -5
- package/lib/gen/zappar.d.ts +12 -0
- package/lib/gen/zappar.js +5 -3
- package/lib/gfx.d.ts +1 -0
- package/lib/gfx.js +4 -0
- package/lib/gl-state-manager.d.ts +9 -0
- package/lib/gl-state-manager.js +35 -0
- package/lib/html-element-source.d.ts +3 -20
- package/lib/html-element-source.js +19 -263
- package/lib/image-process-gl.d.ts +37 -0
- package/lib/image-process-gl.js +298 -0
- package/lib/imagebitmap-camera-source.d.ts +36 -0
- package/lib/imagebitmap-camera-source.js +277 -0
- package/lib/imagetracker.d.ts +28 -0
- package/lib/imagetracker.js +119 -0
- package/lib/index.d.ts +1 -1
- package/lib/mstp-camera-source.d.ts +29 -0
- package/lib/mstp-camera-source.js +230 -0
- package/lib/native.js +119 -8
- package/lib/pipeline.d.ts +13 -3
- package/lib/pipeline.js +95 -26
- package/lib/profile.d.ts +2 -0
- package/lib/profile.js +55 -44
- package/lib/riff-reader.d.ts +18 -0
- package/lib/riff-reader.js +56 -0
- package/lib/sequencerecorder.d.ts +1 -0
- package/lib/sequencerecorder.js +11 -0
- package/lib/sequencesource.d.ts +7 -1
- package/lib/sequencesource.js +89 -47
- package/lib/source.d.ts +6 -4
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/worker-client.js +0 -5
- package/lib/worker-imagebitmap.d.ts +5 -0
- package/lib/worker-imagebitmap.js +63 -0
- package/lib/worker-server.d.ts +0 -5
- package/lib/worker-server.js +120 -30
- package/lib/workerinterface.d.ts +47 -1
- package/lib/zcv.js +117 -135
- package/lib/zcv.wasm +0 -0
- package/package.json +34 -31
- package/umd/e9486c1cdadb21608a4f7e2fa3be9517.wasm +0 -0
- package/umd/zappar-cv.js +1 -9
- package/umd/zappar-cv.worker.js +1 -1
- package/lib/bundleworker-mainthread.d.ts +0 -2
- package/lib/bundleworker-mainthread.js +0 -36
- package/lib/bundleworker-worker.d.ts +0 -3
- package/lib/bundleworker-worker.js +0 -47
- package/umd/5dd5cacd27e6e7da828f.bundleworker.js +0 -1
- 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
|
-
|
|
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
|
-
|
|
250
|
-
let
|
|
251
|
-
|
|
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
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
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
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;
|
package/lib/sequencerecorder.js
CHANGED
|
@@ -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;
|
package/lib/sequencesource.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
}
|
package/lib/sequencesource.js
CHANGED
|
@@ -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
|
-
|
|
59
|
+
let curTime = performance.now();
|
|
60
|
+
if (curTime < this._lastUpdateTime + this._minFrameGapMs)
|
|
43
61
|
return;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
|
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):
|
|
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
|
+
export declare const VERSION = "0.4.0-beta.10";
|
package/lib/version.js
CHANGED
package/lib/worker-client.js
CHANGED
|
@@ -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();
|