edge-impulse-linux 1.19.0 → 1.21.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/build/cli/linux/linux.js +9 -1
- package/build/cli/linux/linux.js.map +1 -1
- package/build/cli/linux/runner-downloader.js +5 -1
- package/build/cli/linux/runner-downloader.js.map +1 -1
- package/build/cli/linux/runner.js +21 -6
- package/build/cli/linux/runner.js.map +1 -1
- package/build/library/classifier/image-classifier.d.ts +2 -0
- package/build/library/classifier/image-classifier.js +84 -54
- package/build/library/classifier/image-classifier.js.map +1 -1
- package/build/library/data-forwarder.d.ts +1 -1
- package/build/library/data-forwarder.js +17 -33
- package/build/library/data-forwarder.js.map +1 -1
- package/build/library/sensors/gstreamer.d.ts +10 -4
- package/build/library/sensors/gstreamer.js +248 -58
- package/build/library/sensors/gstreamer.js.map +1 -1
- package/build/library/sensors/icamera.d.ts +30 -1
- package/build/library/sensors/imagesnap.d.ts +2 -2
- package/build/library/sensors/imagesnap.js +8 -2
- package/build/library/sensors/imagesnap.js.map +1 -1
- package/build/library/sensors/prophesee.d.ts +2 -2
- package/build/library/sensors/prophesee.js +6 -1
- package/build/library/sensors/prophesee.js.map +1 -1
- package/build/library/sensors/sensors-helper.d.ts +3 -0
- package/build/library/sensors/sensors-helper.js +4 -3
- package/build/library/sensors/sensors-helper.js.map +1 -1
- package/build/sdk/studio/sdk/api/adminApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/adminApi.js +4782 -4928
- package/build/sdk/studio/sdk/api/adminApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/authApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/authApi.js +88 -56
- package/build/sdk/studio/sdk/api/authApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/cDNApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/cDNApi.js +76 -53
- package/build/sdk/studio/sdk/api/cDNApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/canaryApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/canaryApi.js +79 -53
- package/build/sdk/studio/sdk/api/canaryApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/classifyApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/classifyApi.js +527 -499
- package/build/sdk/studio/sdk/api/classifyApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/dSPApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/dSPApi.js +938 -942
- package/build/sdk/studio/sdk/api/dSPApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/deploymentApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/deploymentApi.js +680 -603
- package/build/sdk/studio/sdk/api/deploymentApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/devicesApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/devicesApi.js +802 -800
- package/build/sdk/studio/sdk/api/devicesApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/emailVerificationApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/emailVerificationApi.js +184 -190
- package/build/sdk/studio/sdk/api/emailVerificationApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/exportApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/exportApi.js +88 -56
- package/build/sdk/studio/sdk/api/exportApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/featureFlagsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/featureFlagsApi.js +76 -52
- package/build/sdk/studio/sdk/api/featureFlagsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/healthApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/healthApi.js +111 -97
- package/build/sdk/studio/sdk/api/healthApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/impulseApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/impulseApi.js +942 -902
- package/build/sdk/studio/sdk/api/impulseApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/integrationsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/integrationsApi.js +136 -106
- package/build/sdk/studio/sdk/api/integrationsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/jobsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/jobsApi.js +2270 -2326
- package/build/sdk/studio/sdk/api/jobsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/learnApi.d.ts +22 -6
- package/build/sdk/studio/sdk/api/learnApi.js +1597 -1424
- package/build/sdk/studio/sdk/api/learnApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/loginApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/loginApi.js +112 -98
- package/build/sdk/studio/sdk/api/loginApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/metricsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/metricsApi.js +148 -144
- package/build/sdk/studio/sdk/api/metricsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/optimizationApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/optimizationApi.js +844 -844
- package/build/sdk/studio/sdk/api/optimizationApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/organizationBlocksApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/organizationBlocksApi.js +1968 -1550
- package/build/sdk/studio/sdk/api/organizationBlocksApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/organizationCreateProjectApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/organizationCreateProjectApi.js +700 -652
- package/build/sdk/studio/sdk/api/organizationCreateProjectApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/organizationDataApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/organizationDataApi.js +2074 -1985
- package/build/sdk/studio/sdk/api/organizationDataApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/organizationDataCampaignsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/organizationDataCampaignsApi.js +626 -602
- package/build/sdk/studio/sdk/api/organizationDataCampaignsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/organizationJobsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/organizationJobsApi.js +417 -399
- package/build/sdk/studio/sdk/api/organizationJobsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/organizationPipelinesApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/organizationPipelinesApi.js +419 -401
- package/build/sdk/studio/sdk/api/organizationPipelinesApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/organizationPortalsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/organizationPortalsApi.js +372 -352
- package/build/sdk/studio/sdk/api/organizationPortalsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/organizationsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/organizationsApi.js +4024 -4050
- package/build/sdk/studio/sdk/api/organizationsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/performanceCalibrationApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/performanceCalibrationApi.js +586 -560
- package/build/sdk/studio/sdk/api/performanceCalibrationApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/postProcessingApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/postProcessingApi.js +279 -255
- package/build/sdk/studio/sdk/api/postProcessingApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/projectsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/projectsApi.js +2758 -2818
- package/build/sdk/studio/sdk/api/projectsApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/rawDataApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/rawDataApi.js +3055 -3131
- package/build/sdk/studio/sdk/api/rawDataApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/testApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/testApi.js +152 -108
- package/build/sdk/studio/sdk/api/testApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/themesApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/themesApi.js +341 -305
- package/build/sdk/studio/sdk/api/themesApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/thirdPartyAuthApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/thirdPartyAuthApi.js +387 -353
- package/build/sdk/studio/sdk/api/thirdPartyAuthApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/uploadPortalApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/uploadPortalApi.js +375 -355
- package/build/sdk/studio/sdk/api/uploadPortalApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/userApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/userApi.js +2345 -2452
- package/build/sdk/studio/sdk/api/userApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/vlmApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/vlmApi.js +277 -253
- package/build/sdk/studio/sdk/api/vlmApi.js.map +1 -1
- package/build/sdk/studio/sdk/api/whitelabelsApi.d.ts +4 -6
- package/build/sdk/studio/sdk/api/whitelabelsApi.js +408 -398
- package/build/sdk/studio/sdk/api/whitelabelsApi.js.map +1 -1
- package/build/sdk/studio/sdk/model/deployPretrainedModelRequest.d.ts +4 -0
- package/build/sdk/studio/sdk/model/deployPretrainedModelRequest.js +5 -0
- package/build/sdk/studio/sdk/model/deployPretrainedModelRequest.js.map +1 -1
- package/build/sdk/studio/sdk/model/models.d.ts +47 -7
- package/build/sdk/studio/sdk/model/models.js +42 -38
- package/build/sdk/studio/sdk/model/models.js.map +1 -1
- package/build/sdk/studio/sdk/model/uploadPretrainedModelByUrlRequest.d.ts +47 -0
- package/build/sdk/studio/sdk/model/uploadPretrainedModelByUrlRequest.js +55 -0
- package/build/sdk/studio/sdk/model/uploadPretrainedModelByUrlRequest.js.map +1 -0
- package/build/sdk/studio/sdk/model/uploadPretrainedModelRequest.d.ts +4 -0
- package/build/sdk/studio/sdk/model/uploadPretrainedModelRequest.js +5 -0
- package/build/sdk/studio/sdk/model/uploadPretrainedModelRequest.js.map +1 -1
- package/package.json +4 -2
- package/test/gstreamer.test.ts +1487 -3840
- package/test/imx219-csi-on-arduino-unoq-inspect.txt +564 -0
- package/test/imx219-csi-on-arduino-unoq-monitor.txt +285 -0
- package/test/logitech-c920-on-ubuntu-22-parallells.txt +211 -0
- package/test/logitech-c922-on-rpi-bullseye-2.txt +270 -0
- package/test/logitech-c922-on-rpi-bullseye.txt +331 -0
- package/test/macbook-pro-w-internal-and-external-cam-inspect.txt +1496 -0
- package/test/macbook-pro-w-internal-and-external-cam-monitor.txt +209 -0
- package/test/nvidia-jetson-w-csi-camera.txt +94 -0
- package/test/nvidia-jetson-w-logitech-c922-monitor.txt +204 -0
- package/test/nvidia-orin-w-basler-camera-inspect.txt +859 -0
- package/test/nvidia-orin-w-basler-camera-pylonsrc.txt +806 -0
- package/test/qualcomm-rb3-gen-2-ubuntu-no-external-camera-inspect-qtiqmmfsrc.txt +438 -0
- package/test/qualcomm-rb3-gen-2-ubuntu-no-external-camera-inspect.txt +958 -0
- package/test/qualcomm-rb3-gen-2-ubuntu-no-external-camera-monitor.txt +159 -0
- package/test/rb1-debian-inspect.txt +568 -0
- package/test/rb1-debian-libcamera-monitor.txt +190 -0
- package/test/rpi-cam-v3-c920-webcam-bookworm-no-libcamerasrc.txt +383 -0
- package/test/rpi4-trixie-csi-gst-device-monitor.txt +1110 -0
- package/test/rpi4-trixie-csi-gst-inspect.txt +1379 -0
- package/test/rpi5-with-csi-imx500-camera-monitor.txt +3617 -0
- package/test/rpi5-with-csi-imx708-monitor.txt +2277 -0
- package/test/usb-camera-on-rpi-w-image-jpg.txt +130 -0
- /package/test/{qualcomm-rb3-inspect-qtiqmmfsrc.txt → qualcomm-rb3-gen-2-qimp-linux-1-2-with-logitech-brio-inspect-qtiqmmfsrc.txt} +0 -0
- /package/test/{qualcomm-rb3-inspect.txt → qualcomm-rb3-gen-2-qimp-linux-1-2-with-logitech-brio-inspect.txt} +0 -0
- /package/test/{qualcomm-rb3-monitor-brio.txt → qualcomm-rb3-gen-2-qimp-linux-1-2-with-logitech-brio-monitor.txt} +0 -0
- /package/test/{triple-vision-camera-inspect.txt → triple-vision-ai-industrial-camera-inspect.txt} +0 -0
- /package/test/{triple-vision-camera-monitor.txt → triple-vision-ai-industrial-camera-monitor.txt} +0 -0
|
@@ -20,13 +20,14 @@ const DEFAULT_GST_VIDEO_SOURCE = 'v4l2src';
|
|
|
20
20
|
class GStreamer extends tsee_1.EventEmitter {
|
|
21
21
|
constructor(verbose, options) {
|
|
22
22
|
super();
|
|
23
|
-
this.
|
|
23
|
+
this._originalAndRgbFilesSeen = new Set();
|
|
24
24
|
this._handledFiles = {};
|
|
25
25
|
this._processing = false;
|
|
26
26
|
this._mode = 'default';
|
|
27
27
|
this._isStarted = false;
|
|
28
28
|
this._isRestarting = false;
|
|
29
29
|
this._emitsOriginalSizeImages = false;
|
|
30
|
+
this._emitsRgbBuffers = false;
|
|
30
31
|
this._lastGstLaunchCommand = '';
|
|
31
32
|
this._imagesReceived = 0;
|
|
32
33
|
this._offset = 0;
|
|
@@ -35,6 +36,10 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
35
36
|
this._spawnHelper = options?.spawnHelperOverride || spawn_helper_1.spawnHelper;
|
|
36
37
|
this._modeOverride = options?.modeOverride;
|
|
37
38
|
this._profiling = options?.profiling || false;
|
|
39
|
+
this._overrideColorFormat = options?.colorFormat;
|
|
40
|
+
this._outputRgbBuffers = options?.dontOutputRgbBuffers === true ?
|
|
41
|
+
false :
|
|
42
|
+
true;
|
|
38
43
|
if (options?.dontRunCleanupLoop === true) {
|
|
39
44
|
// skip cleanup loop
|
|
40
45
|
}
|
|
@@ -60,31 +65,43 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
60
65
|
console.log(PREFIX, 'checking for /etc/os-release');
|
|
61
66
|
osRelease = await fs_1.default.promises.readFile('/etc/os-release', 'utf-8');
|
|
62
67
|
}
|
|
68
|
+
else {
|
|
69
|
+
// so we don't need to check for undefined below
|
|
70
|
+
osRelease = '';
|
|
71
|
+
}
|
|
63
72
|
let firmwareModel;
|
|
64
73
|
// using /proc/device-tree as recommended in user space.
|
|
65
74
|
if (await this.exists('/proc/device-tree/model')) {
|
|
66
75
|
firmwareModel = await fs_1.default.promises.readFile('/proc/device-tree/model', 'utf-8');
|
|
67
76
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (osRelease.indexOf('ID=raspbian') > -1) {
|
|
72
|
-
this._mode = 'rpi';
|
|
73
|
-
}
|
|
74
|
-
if (firmwareModel && firmwareModel.indexOf('Raspberry Pi') > -1) {
|
|
75
|
-
this._mode = 'rpi';
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (firmwareModel && firmwareModel.indexOf('Microchip SAMA7G5') > -1) {
|
|
80
|
-
this._mode = 'microchip';
|
|
77
|
+
else {
|
|
78
|
+
// so we don't need to check for undefined below
|
|
79
|
+
firmwareModel = '';
|
|
81
80
|
}
|
|
82
|
-
|
|
81
|
+
if (firmwareModel.indexOf('RB3gen2') > -1 && firmwareModel.indexOf('vision') > -1) {
|
|
83
82
|
this._mode = 'qualcomm-rb3gen2';
|
|
84
83
|
}
|
|
85
|
-
else if (firmwareModel
|
|
84
|
+
else if (firmwareModel.indexOf('Qualcomm') > -1 && firmwareModel.indexOf('Yupik') > -1) {
|
|
86
85
|
this._mode = 'qualcomm-yupik';
|
|
87
86
|
}
|
|
87
|
+
else if (firmwareModel.indexOf('Raspberry Pi') > -1) {
|
|
88
|
+
if (((osRelease.indexOf('bullseye') > -1) || (osRelease.indexOf('bookworm') > -1))
|
|
89
|
+
&& (osRelease.indexOf('ID=raspbian') === -1)) {
|
|
90
|
+
this._mode = 'rpi';
|
|
91
|
+
}
|
|
92
|
+
else if (osRelease.indexOf('trixie') > -1) {
|
|
93
|
+
this._mode = 'rpi';
|
|
94
|
+
}
|
|
95
|
+
// override to rpi5 if needed
|
|
96
|
+
if (firmwareModel.indexOf('Raspberry Pi 5') > -1) {
|
|
97
|
+
this._mode = 'rpi5';
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if ((firmwareModel.indexOf('Arduino') > -1 && firmwareModel.indexOf('Imola') > -1) ||
|
|
101
|
+
// this may be incorrect on the another platforms in the future
|
|
102
|
+
(process.env.EI_CLI_ENV === 'arduino')) {
|
|
103
|
+
this._mode = 'unoq';
|
|
104
|
+
}
|
|
88
105
|
this._mode = (this._modeOverride) ? this._modeOverride : this._mode;
|
|
89
106
|
}
|
|
90
107
|
async listDevices() {
|
|
@@ -240,16 +257,20 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
240
257
|
}
|
|
241
258
|
let lastPhoto = 0;
|
|
242
259
|
let nextFrame = Date.now();
|
|
243
|
-
this.
|
|
260
|
+
this._originalAndRgbFilesSeen = new Set();
|
|
244
261
|
this._watcher = fs_1.default.watch(this._tempDir, async (eventType, fileName) => {
|
|
245
262
|
if (eventType !== 'rename')
|
|
246
263
|
return;
|
|
247
264
|
if (fileName === null)
|
|
248
265
|
return;
|
|
249
|
-
if (!(fileName.endsWith('.jpeg') || fileName.endsWith('.jpg')))
|
|
266
|
+
if (!(fileName.endsWith('.jpeg') || fileName.endsWith('.jpg') || fileName.endsWith('.rgb')))
|
|
250
267
|
return;
|
|
251
268
|
if (fileName.startsWith('original')) {
|
|
252
|
-
this.
|
|
269
|
+
this._originalAndRgbFilesSeen.add(fileName);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (fileName.endsWith('.rgb')) {
|
|
273
|
+
this._originalAndRgbFilesSeen.add(fileName);
|
|
253
274
|
return;
|
|
254
275
|
}
|
|
255
276
|
if (!this._tempDir)
|
|
@@ -257,10 +278,11 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
257
278
|
if (this._handledFiles[fileName])
|
|
258
279
|
return;
|
|
259
280
|
this._imagesReceived++;
|
|
281
|
+
const tempDir = this._tempDir; // this can get unset later on -> so cache here
|
|
260
282
|
// not next frame yet?
|
|
261
283
|
if (this._processing || Date.now() < nextFrame) {
|
|
262
284
|
this._handledFiles[fileName] = true;
|
|
263
|
-
await this.safeUnlinkFile(path_1.default.join(
|
|
285
|
+
await this.safeUnlinkFile(path_1.default.join(tempDir, fileName));
|
|
264
286
|
return;
|
|
265
287
|
}
|
|
266
288
|
nextFrame = Date.now() + options.intervalMs;
|
|
@@ -269,7 +291,7 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
269
291
|
this._handledFiles[fileName] = true;
|
|
270
292
|
const originalName = fileName.replace('resized', 'original');
|
|
271
293
|
if (this._emitsOriginalSizeImages) {
|
|
272
|
-
if (!this.
|
|
294
|
+
if (!this._originalAndRgbFilesSeen.has(originalName)) {
|
|
273
295
|
let waitForOriginalStart = Date.now();
|
|
274
296
|
if (this._verbose) {
|
|
275
297
|
console.log(PREFIX, `Waiting for original file "${originalName}"...`);
|
|
@@ -277,13 +299,13 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
277
299
|
await new Promise(async (resolve, reject) => {
|
|
278
300
|
let start = Date.now();
|
|
279
301
|
while (1) {
|
|
280
|
-
if (this.
|
|
302
|
+
if (this._originalAndRgbFilesSeen.has(originalName)) {
|
|
281
303
|
return resolve();
|
|
282
304
|
}
|
|
283
305
|
if (Date.now() - start > 1000) {
|
|
284
306
|
return reject(`Did not find original image ("${originalName}") within 1sec`);
|
|
285
307
|
}
|
|
286
|
-
await this.wait(
|
|
308
|
+
await this.wait(1);
|
|
287
309
|
}
|
|
288
310
|
});
|
|
289
311
|
if (this._verbose) {
|
|
@@ -292,19 +314,46 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
292
314
|
}
|
|
293
315
|
}
|
|
294
316
|
}
|
|
317
|
+
const rgbName = fileName.replace('.jpg', '.rgb');
|
|
318
|
+
if (this._emitsRgbBuffers) {
|
|
319
|
+
if (!this._originalAndRgbFilesSeen.has(rgbName)) {
|
|
320
|
+
let waitForRgbStart = Date.now();
|
|
321
|
+
if (this._verbose) {
|
|
322
|
+
console.log(PREFIX, `Waiting for RGB file "${rgbName}"...`);
|
|
323
|
+
}
|
|
324
|
+
await new Promise(async (resolve, reject) => {
|
|
325
|
+
let start = Date.now();
|
|
326
|
+
while (1) {
|
|
327
|
+
if (this._originalAndRgbFilesSeen.has(rgbName)) {
|
|
328
|
+
return resolve();
|
|
329
|
+
}
|
|
330
|
+
if (Date.now() - start > 1000) {
|
|
331
|
+
return reject(`Did not find RGB image ("${rgbName}") within 1sec`);
|
|
332
|
+
}
|
|
333
|
+
await this.wait(1);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
if (this._verbose) {
|
|
337
|
+
console.log(PREFIX, `Waiting for RGB file "${rgbName}" OK ` +
|
|
338
|
+
`(took ${Date.now() - waitForRgbStart}ms.)`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
295
342
|
if (lastPhoto !== 0 && this._verbose) {
|
|
296
343
|
console.log(PREFIX, 'Got snapshot', fileName, 'time since last:', (Date.now() - lastPhoto) + 'ms.', 'size');
|
|
297
344
|
}
|
|
298
345
|
if (this._keepAliveTimeout) {
|
|
299
346
|
clearTimeout(this._keepAliveTimeout);
|
|
300
347
|
}
|
|
301
|
-
const tempDir = this._tempDir;
|
|
302
348
|
try {
|
|
303
|
-
let [imgBuffer, originalImgBuffer] = await Promise.all([
|
|
349
|
+
let [imgBuffer, originalImgBuffer, rgbBuffer,] = await Promise.all([
|
|
304
350
|
fs_1.default.promises.readFile(path_1.default.join(tempDir, fileName)),
|
|
305
351
|
this._emitsOriginalSizeImages ?
|
|
306
352
|
fs_1.default.promises.readFile(path_1.default.join(tempDir, originalName)) :
|
|
307
353
|
null,
|
|
354
|
+
this._emitsRgbBuffers ?
|
|
355
|
+
fs_1.default.promises.readFile(path_1.default.join(tempDir, rgbName)) :
|
|
356
|
+
null,
|
|
308
357
|
]);
|
|
309
358
|
// hash not changed? don't emit another event (streamer does this on Rpi)
|
|
310
359
|
let hash = crypto_1.default.createHash('sha256').update(imgBuffer).digest('hex');
|
|
@@ -312,7 +361,12 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
312
361
|
// snapshot() sends out the original size image
|
|
313
362
|
this.emit('snapshot', originalImgBuffer || imgBuffer, path_1.default.basename(fileName));
|
|
314
363
|
// snapshotForInference() sends out the resized image
|
|
315
|
-
this.emit('snapshotForInference',
|
|
364
|
+
this.emit('snapshotForInference', {
|
|
365
|
+
imageForInferenceJpg: imgBuffer,
|
|
366
|
+
filename: path_1.default.basename(fileName),
|
|
367
|
+
imageFromCameraJpg: originalImgBuffer || imgBuffer,
|
|
368
|
+
imageForInferenceRgb: rgbBuffer || undefined,
|
|
369
|
+
});
|
|
316
370
|
lastPhoto = Date.now();
|
|
317
371
|
// 2 seconds no new data? trigger timeout
|
|
318
372
|
if (this._keepAliveTimeout) {
|
|
@@ -341,7 +395,13 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
341
395
|
(async () => {
|
|
342
396
|
if (originalName) {
|
|
343
397
|
await this.safeUnlinkFile(path_1.default.join(tempDir, originalName));
|
|
344
|
-
this.
|
|
398
|
+
this._originalAndRgbFilesSeen.delete(originalName);
|
|
399
|
+
}
|
|
400
|
+
})(),
|
|
401
|
+
(async () => {
|
|
402
|
+
if (rgbName) {
|
|
403
|
+
await this.safeUnlinkFile(path_1.default.join(tempDir, rgbName));
|
|
404
|
+
this._originalAndRgbFilesSeen.delete(rgbName);
|
|
345
405
|
}
|
|
346
406
|
})(),
|
|
347
407
|
]);
|
|
@@ -376,9 +436,25 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
376
436
|
return;
|
|
377
437
|
}
|
|
378
438
|
else {
|
|
439
|
+
const errMsg = `GStreamer (gst-launch-1.0) stopped before emitting any images. This most likely ` +
|
|
440
|
+
`means that the launch command is incorrect or that your camera is unresponsive. Here is the launch command:\n\n` +
|
|
441
|
+
`${this._lastGstLaunchCommand}\n\n` +
|
|
442
|
+
`You can try one of the following:\n\n` +
|
|
443
|
+
`* If your camera used to work:\n` +
|
|
444
|
+
` * Disconnect and reconnect the camera (if you use an external camera)\n` +
|
|
445
|
+
` * Kill all other GStreamer commands, via: 'sudo killall gst-launch-1.0'\n` +
|
|
446
|
+
`* Run with '--verbose' to see the raw GStreamer output. It might contain a hint why the process fails.\n` +
|
|
447
|
+
`* Run with '--dont-output-rgb-buffers' - this will disable RGB output buffer creation which can help with ` +
|
|
448
|
+
`targets that advertise RGB capabilities on the video source, but don't actually support this.\n\n` +
|
|
449
|
+
`If this does not resolve your issue, then please open a forum post at https://forum.edgeimpulse.com and include:\n\n` +
|
|
450
|
+
`* Your device, operating system, what camera you're using, and how the camera is connected (e.g. USB, CSI)\n` +
|
|
451
|
+
`* The launch command (above)\n` +
|
|
452
|
+
`* The verbose output (run this application with --verbose)\n` +
|
|
453
|
+
`* The output of 'gst-device-monitor-1.0'\n` +
|
|
454
|
+
`* The output of 'gst-inspect-1.0'`;
|
|
379
455
|
if (this._imagesReceived === 0 && this._lastGstLaunchCommand) {
|
|
380
456
|
reject(`Capture process failed with code ${code}\n\n` +
|
|
381
|
-
|
|
457
|
+
`${errMsg}`);
|
|
382
458
|
}
|
|
383
459
|
else {
|
|
384
460
|
reject('Capture process failed with code ' + code);
|
|
@@ -429,6 +505,7 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
429
505
|
}
|
|
430
506
|
async getGstreamerLaunchCommand(device, dimensions, inferenceDims) {
|
|
431
507
|
this._emitsOriginalSizeImages = false;
|
|
508
|
+
this._emitsRgbBuffers = false;
|
|
432
509
|
if (device.id === CUSTOM_GST_LAUNCH_COMMAND) {
|
|
433
510
|
if (!this._customLaunchCommand) {
|
|
434
511
|
throw new Error('_customLaunchCommand is null');
|
|
@@ -443,7 +520,7 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
443
520
|
pipeline: customArgs.join(' '),
|
|
444
521
|
};
|
|
445
522
|
}
|
|
446
|
-
// now we need to determine the resolution... we want something as close as possible to dimensions.
|
|
523
|
+
// now we need to determine the resolution... we want something as close as possible to dimensions.
|
|
447
524
|
let caps = device.caps.filter(c => {
|
|
448
525
|
return c.width >= dimensions.width && c.height >= dimensions.height;
|
|
449
526
|
}).sort((a, b) => {
|
|
@@ -474,20 +551,28 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
474
551
|
if (device.id) {
|
|
475
552
|
videoSource.push(`device=${device.id}`);
|
|
476
553
|
}
|
|
477
|
-
if ((this._mode === 'rpi') || (this._mode === '
|
|
478
|
-
//
|
|
554
|
+
if ((this._mode === 'rpi') || (this._mode === 'rpi5') || device.videoSource === 'libcamerasrc') {
|
|
555
|
+
// libcamera devices don't have id set (or have some unique on Raspberry Pi or Microchip)
|
|
479
556
|
if ((!device.id)
|
|
480
557
|
|| (device.name.indexOf('unicam') > -1)
|
|
481
558
|
|| (device.name.indexOf('bcm2835-isp') > -1)) {
|
|
482
559
|
videoSource = [
|
|
483
560
|
...(this._profiling ? ['-m'] : []),
|
|
484
561
|
'libcamerasrc',
|
|
562
|
+
...device.name ? ['camera-name="' + device.name + '"'] : [],
|
|
485
563
|
];
|
|
486
564
|
const hasPlugin = await this.hasGstPlugin('libcamerasrc');
|
|
487
565
|
if (!hasPlugin) {
|
|
488
566
|
throw new Error('Missing "libcamerasrc" gstreamer element. Install via `sudo apt install -y gstreamer1.0-libcamera`');
|
|
489
567
|
}
|
|
490
568
|
}
|
|
569
|
+
// FIXME: dirty hack for IPASoft on QRB2210
|
|
570
|
+
// Some resolutions reported by camera causes the pipeline to hang. To fix that, it seems
|
|
571
|
+
// we need to increase width and/or height by 8 pixels. This hack should be removed once
|
|
572
|
+
// the hardware driver for ISP on QRB2210 is released.
|
|
573
|
+
if (this._mode === 'unoq') {
|
|
574
|
+
cap.width += 8;
|
|
575
|
+
}
|
|
491
576
|
}
|
|
492
577
|
else if ((this._mode === 'qualcomm-rb3gen2') || (this._mode === 'qualcomm-yupik')) {
|
|
493
578
|
videoSource = [
|
|
@@ -503,6 +588,24 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
503
588
|
'pylonsrc',
|
|
504
589
|
];
|
|
505
590
|
}
|
|
591
|
+
const frameReadyArgs = this._profiling ? [`!`, `identity name=frame_ready silent=false`] : [];
|
|
592
|
+
const jpgencDoneArgs = this._profiling ? [`!`, `identity name=jpegenc_done silent=false`] : [];
|
|
593
|
+
const resizeDoneArgs = this._profiling ? [`!`, `identity name=resize_done silent=false`] : [];
|
|
594
|
+
let teeToBothResizedJpgAndRgb;
|
|
595
|
+
let videoFormat = '';
|
|
596
|
+
if (this._outputRgbBuffers) {
|
|
597
|
+
teeToBothResizedJpgAndRgb = [
|
|
598
|
+
`tee name=u`,
|
|
599
|
+
`u. ! queue ! jpegenc ${jpgencDoneArgs.join(' ')} ! multifilesink location=resized%05d.jpg post-messages=true sync=false `,
|
|
600
|
+
`u. ! queue ! multifilesink location=resized%05d.rgb post-messages=true sync=false `,
|
|
601
|
+
];
|
|
602
|
+
videoFormat = ',format=RGB'; // Don't do this if outputRgbBuffers is RGB, because we don't want to force RGB video format
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
teeToBothResizedJpgAndRgb = [
|
|
606
|
+
`jpegenc ${jpgencDoneArgs.join(' ')} ! multifilesink location=resized%05d.jpg post-messages=true sync=false`,
|
|
607
|
+
];
|
|
608
|
+
}
|
|
506
609
|
let cropArgs = [];
|
|
507
610
|
if (inferenceDims) {
|
|
508
611
|
// fast path for fit-shortest and squash
|
|
@@ -514,14 +617,14 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
514
617
|
`!`,
|
|
515
618
|
`videoscale`, `method=lanczos`,
|
|
516
619
|
`!`,
|
|
517
|
-
`video/x-raw,width=${inferenceDims.width},height=${inferenceDims.height}`,
|
|
620
|
+
`video/x-raw${videoFormat},width=${inferenceDims.width},height=${inferenceDims.height}`,
|
|
518
621
|
]);
|
|
519
622
|
}
|
|
520
|
-
else if (inferenceDims.resizeMode === 'squash' || inferenceDims.resizeMode === 'none' /* old model */) {
|
|
623
|
+
else if (inferenceDims.resizeMode === 'squash' || inferenceDims.resizeMode === 'none' /* old model -> squash */) {
|
|
521
624
|
cropArgs.push(`!`);
|
|
522
625
|
cropArgs.push(`videoscale`, `method=lanczos`);
|
|
523
626
|
cropArgs.push(`!`);
|
|
524
|
-
cropArgs.push(`video/x-raw,width=${inferenceDims.width},height=${inferenceDims.height}`);
|
|
627
|
+
cropArgs.push(`video/x-raw${videoFormat},width=${inferenceDims.width},height=${inferenceDims.height}`);
|
|
525
628
|
}
|
|
526
629
|
}
|
|
527
630
|
let args;
|
|
@@ -532,14 +635,35 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
532
635
|
`video/x-raw,width=${cap.width},height=${cap.height},format=YUY2`
|
|
533
636
|
]);
|
|
534
637
|
}
|
|
638
|
+
else if (device.videoSource === 'qtiqmmfsrc') {
|
|
639
|
+
videoSource = videoSource.concat([
|
|
640
|
+
`!`,
|
|
641
|
+
`video/x-raw,width=${cap.width},height=${cap.height},format=NV12`
|
|
642
|
+
]);
|
|
643
|
+
}
|
|
644
|
+
else if (this._mode === 'rpi5') {
|
|
645
|
+
// on RPi 5 we need to set color format
|
|
646
|
+
let colorFormat = '';
|
|
647
|
+
if (this._overrideColorFormat) {
|
|
648
|
+
colorFormat = this._overrideColorFormat;
|
|
649
|
+
}
|
|
650
|
+
else if (cap.formats && cap.formats.indexOf('YUY2') > -1) {
|
|
651
|
+
colorFormat = 'YUY2';
|
|
652
|
+
}
|
|
653
|
+
else if (cap.formats) {
|
|
654
|
+
throw new Error('Detected RPi 5 camera. Please provide the color format with `--camera-color-format`, supported formats: ' + cap.formats.join(', '));
|
|
655
|
+
}
|
|
656
|
+
videoSource = videoSource.concat([
|
|
657
|
+
`!`,
|
|
658
|
+
`video/x-raw,width=${cap.width},height=${cap.height},format=${colorFormat}`
|
|
659
|
+
]);
|
|
660
|
+
}
|
|
535
661
|
else {
|
|
536
662
|
videoSource = videoSource.concat([
|
|
537
663
|
`!`,
|
|
538
664
|
`video/x-raw,width=${cap.width},height=${cap.height}`
|
|
539
665
|
]);
|
|
540
666
|
}
|
|
541
|
-
let frameReadyArgs = this._profiling ? [`!`, `identity name=frame_ready silent=false`] : [];
|
|
542
|
-
let jpgencDoneArgs = this._profiling ? [`!`, `identity name=jpegenc_done silent=false`] : [];
|
|
543
667
|
if (cropArgs.length === 0) {
|
|
544
668
|
args = videoSource.concat([
|
|
545
669
|
...frameReadyArgs,
|
|
@@ -557,11 +681,9 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
557
681
|
let resized = [
|
|
558
682
|
`t. ! queue`,
|
|
559
683
|
...cropArgs,
|
|
684
|
+
...resizeDoneArgs,
|
|
560
685
|
`!`,
|
|
561
|
-
|
|
562
|
-
...jpgencDoneArgs,
|
|
563
|
-
`!`,
|
|
564
|
-
`multifilesink location=resized%05d.jpg post-messages=true sync=false`,
|
|
686
|
+
...teeToBothResizedJpgAndRgb,
|
|
565
687
|
];
|
|
566
688
|
args = videoSource.concat([
|
|
567
689
|
...frameReadyArgs,
|
|
@@ -573,15 +695,51 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
573
695
|
...resized,
|
|
574
696
|
]);
|
|
575
697
|
this._emitsOriginalSizeImages = true;
|
|
698
|
+
if (this._outputRgbBuffers) {
|
|
699
|
+
this._emitsRgbBuffers = true;
|
|
700
|
+
}
|
|
576
701
|
}
|
|
577
702
|
}
|
|
578
703
|
else if (cap.type === 'image/jpeg') {
|
|
579
|
-
|
|
704
|
+
videoSource = videoSource.concat([
|
|
580
705
|
`!`,
|
|
581
706
|
`image/jpeg,width=${cap.width},height=${cap.height}`,
|
|
582
|
-
`!`,
|
|
583
|
-
`multifilesink location=resized%05d.jpg post-messages=true sync=false`
|
|
584
707
|
]);
|
|
708
|
+
if (cropArgs.length === 0) {
|
|
709
|
+
args = videoSource.concat([
|
|
710
|
+
...frameReadyArgs,
|
|
711
|
+
`!`,
|
|
712
|
+
`multifilesink`,
|
|
713
|
+
`location=resized%05d.jpg`,
|
|
714
|
+
`post-messages=true`,
|
|
715
|
+
`sync=false`,
|
|
716
|
+
]);
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
let original = `t. ! queue ! multifilesink location=original%05d.jpg post-messages=true sync=false`;
|
|
720
|
+
let resized = [
|
|
721
|
+
`t. ! queue`,
|
|
722
|
+
`!`,
|
|
723
|
+
`jpegdec`,
|
|
724
|
+
`!`,
|
|
725
|
+
`videoconvert`,
|
|
726
|
+
...cropArgs,
|
|
727
|
+
...resizeDoneArgs,
|
|
728
|
+
`!`,
|
|
729
|
+
...teeToBothResizedJpgAndRgb,
|
|
730
|
+
];
|
|
731
|
+
args = videoSource.concat([
|
|
732
|
+
...frameReadyArgs,
|
|
733
|
+
`!`,
|
|
734
|
+
`tee name=t`,
|
|
735
|
+
original,
|
|
736
|
+
...resized,
|
|
737
|
+
]);
|
|
738
|
+
this._emitsOriginalSizeImages = true;
|
|
739
|
+
if (this._outputRgbBuffers) {
|
|
740
|
+
this._emitsRgbBuffers = true;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
585
743
|
}
|
|
586
744
|
else if (cap.type === 'nvarguscamerasrc') {
|
|
587
745
|
args = [
|
|
@@ -595,7 +753,8 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
595
753
|
}
|
|
596
754
|
return {
|
|
597
755
|
command: 'gst-launch-1.0',
|
|
598
|
-
|
|
756
|
+
// replace multiple spaces with one space
|
|
757
|
+
pipeline: args.join(' ').trim().replace(/(\s+)/g, ' '),
|
|
599
758
|
};
|
|
600
759
|
}
|
|
601
760
|
async stop() {
|
|
@@ -607,7 +766,10 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
607
766
|
this._captureProcess.on('close', code => {
|
|
608
767
|
if (this._watcher) {
|
|
609
768
|
this._watcher.on('close', async () => {
|
|
610
|
-
|
|
769
|
+
try {
|
|
770
|
+
await this.cleanupTempDirAsync();
|
|
771
|
+
}
|
|
772
|
+
catch (ex) { /* noop */ }
|
|
611
773
|
});
|
|
612
774
|
this._watcher.close();
|
|
613
775
|
}
|
|
@@ -696,7 +858,8 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
696
858
|
if (!currDevice)
|
|
697
859
|
continue;
|
|
698
860
|
if (l.startsWith('name :')) {
|
|
699
|
-
|
|
861
|
+
// extract name from the l between 'name : ' and '\n', because name may contain colons as well
|
|
862
|
+
currDevice.name = l.split(':').slice(1).join(':').trim();
|
|
700
863
|
continue;
|
|
701
864
|
}
|
|
702
865
|
if (l.startsWith('class :')) {
|
|
@@ -731,6 +894,12 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
731
894
|
if (currDevice.videoSource === 'pipewiresrc') {
|
|
732
895
|
currDevice.videoSource = DEFAULT_GST_VIDEO_SOURCE;
|
|
733
896
|
}
|
|
897
|
+
if (currDevice.videoSource === 'avfvideosrc') {
|
|
898
|
+
const m = l.match(/gst-launch-1.0 avfvideosrc device-index=(\d+) \!/);
|
|
899
|
+
if (m && m.length >= 2) {
|
|
900
|
+
currDevice.videoSource = `avfvideosrc device-index=${m[1]}`;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
734
903
|
}
|
|
735
904
|
}
|
|
736
905
|
}
|
|
@@ -742,6 +911,7 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
742
911
|
let width = (l.match(/width=[^\d]+(\d+)/) || [])[1];
|
|
743
912
|
let height = (l.match(/height=[^\d]+(\d+)/) || [])[1];
|
|
744
913
|
let framerate = (l.match(/framerate=[^\d]+(\d+)/) || [])[1];
|
|
914
|
+
let format = (l.match(/format=([a-zA-Z0-9]+)/) || [])[1];
|
|
745
915
|
// Rpi on bullseye has lines like this..
|
|
746
916
|
// eslint-disable-next-line @stylistic/max-len
|
|
747
917
|
// image/jpeg, width=160, height=120, pixel-aspect-ratio=1/1, framerate={ (fraction)30/1, (fraction)24/1, (fraction)20/1, (fraction)15/1, (fraction)10/1, (fraction)15/2, (fraction)5/1 }
|
|
@@ -759,10 +929,11 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
759
929
|
width: Number(width || '0'),
|
|
760
930
|
height: Number(height || '0'),
|
|
761
931
|
framerate: Number(framerate || '0'),
|
|
932
|
+
formats: format ? [format] : []
|
|
762
933
|
};
|
|
763
934
|
return r;
|
|
764
935
|
});
|
|
765
|
-
if (this._mode === 'rpi' || this._mode === '
|
|
936
|
+
if (this._mode === 'rpi' || this._mode === 'rpi5' || d.videoSource === 'libcamerasrc') { // no framerate here...
|
|
766
937
|
c = c.filter(x => x.width && x.height);
|
|
767
938
|
}
|
|
768
939
|
else if (d.name === 'RZG2L_CRU') {
|
|
@@ -780,14 +951,23 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
780
951
|
else {
|
|
781
952
|
c = c.filter(x => x.width && x.height && x.framerate);
|
|
782
953
|
}
|
|
954
|
+
// get list of all formats form the c list
|
|
955
|
+
const uniqueFormats = Array.from(new Set(c.map(cap => cap.formats).flat()));
|
|
783
956
|
c = c.reduce((curr, o) => {
|
|
784
|
-
// deduplicate caps
|
|
785
|
-
|
|
957
|
+
// deduplicate caps, prioritize 'video/x-raw' type
|
|
958
|
+
const existingIndex = curr.findIndex(obj => obj.framerate === o.framerate &&
|
|
786
959
|
obj.width === o.width &&
|
|
787
|
-
obj.height === o.height
|
|
788
|
-
|
|
960
|
+
obj.height === o.height);
|
|
961
|
+
// store all supported formats (YUY2 etc.)
|
|
962
|
+
if (uniqueFormats) {
|
|
963
|
+
o.formats = uniqueFormats.filter((format) => format !== undefined);
|
|
964
|
+
}
|
|
965
|
+
if (existingIndex === -1) {
|
|
789
966
|
curr.push(o);
|
|
790
967
|
}
|
|
968
|
+
else if (o.type === 'video/x-raw' && curr[existingIndex].type !== 'video/x-raw') {
|
|
969
|
+
curr[existingIndex] = o;
|
|
970
|
+
}
|
|
791
971
|
return curr;
|
|
792
972
|
}, []);
|
|
793
973
|
d.caps = c;
|
|
@@ -804,7 +984,7 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
804
984
|
// Qualcomm has their own plugin, query its too
|
|
805
985
|
// because listQtiqmmsrc* returns hardcoded devices ONLY if a specific gst plugin
|
|
806
986
|
// is available we need to detect device type before, as it may be RubikPi, RB3Gen2 or
|
|
807
|
-
// any other with IMSDK loaded and
|
|
987
|
+
// any other with IMSDK loaded and unknown cameras
|
|
808
988
|
if (this._mode === 'qualcomm-rb3gen2') {
|
|
809
989
|
devices = devices.concat(await this.listQtiqmmsrcDevices());
|
|
810
990
|
}
|
|
@@ -822,10 +1002,18 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
822
1002
|
videoSource: d.videoSource,
|
|
823
1003
|
};
|
|
824
1004
|
});
|
|
825
|
-
// deduplicate (by id)
|
|
1005
|
+
// deduplicate (by id if present, otherwise by name)
|
|
826
1006
|
mapped = mapped.reduce((curr, m) => {
|
|
827
|
-
if (
|
|
828
|
-
|
|
1007
|
+
if (m.id) {
|
|
1008
|
+
if (curr.find(x => x.id === m.id)) {
|
|
1009
|
+
return curr;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
else if (m.name) {
|
|
1013
|
+
if (curr.find(x => x.name === m.name && !x.id)) {
|
|
1014
|
+
return curr;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
829
1017
|
curr.push(m);
|
|
830
1018
|
return curr;
|
|
831
1019
|
}, []);
|
|
@@ -1253,6 +1441,8 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
1253
1441
|
const cropTop = Math.max(0, Math.floor((srcH - cropH) / 2));
|
|
1254
1442
|
const cropBottom = Math.max(0, srcH - cropH - cropTop);
|
|
1255
1443
|
return {
|
|
1444
|
+
width: cropW,
|
|
1445
|
+
height: cropH,
|
|
1256
1446
|
left: cropLeft,
|
|
1257
1447
|
right: cropRight,
|
|
1258
1448
|
top: cropTop,
|
|
@@ -1277,7 +1467,7 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
1277
1467
|
}
|
|
1278
1468
|
let filesToUnlink = [];
|
|
1279
1469
|
// copy as we're manipulating this set
|
|
1280
|
-
for (let originalFileName of Array.from(this.
|
|
1470
|
+
for (let originalFileName of Array.from(this._originalAndRgbFilesSeen)) {
|
|
1281
1471
|
let originalNumberMatch = originalFileName.match(/(\d+)/);
|
|
1282
1472
|
let originalNumber = originalNumberMatch ? Number(originalNumberMatch[1]) : NaN;
|
|
1283
1473
|
if (isNaN(originalNumber)) {
|
|
@@ -1292,13 +1482,13 @@ class GStreamer extends tsee_1.EventEmitter {
|
|
|
1292
1482
|
filesToUnlink.push(originalFileName);
|
|
1293
1483
|
}
|
|
1294
1484
|
if (this._verbose) {
|
|
1295
|
-
console.log(PREFIX, `Unlinking ${filesToUnlink.length} original files...`);
|
|
1485
|
+
console.log(PREFIX, `Unlinking ${filesToUnlink.length} original / RGB files...`);
|
|
1296
1486
|
}
|
|
1297
1487
|
if (filesToUnlink.length > 0) {
|
|
1298
1488
|
const tempDir = this._tempDir;
|
|
1299
1489
|
await (0, async_pool_1.asyncPool)(10, filesToUnlink, async (originalFileName) => {
|
|
1300
1490
|
await this.safeUnlinkFile(path_1.default.join(tempDir, originalFileName));
|
|
1301
|
-
this.
|
|
1491
|
+
this._originalAndRgbFilesSeen.delete(originalFileName);
|
|
1302
1492
|
});
|
|
1303
1493
|
}
|
|
1304
1494
|
}
|