edge-impulse-linux 1.18.3 → 1.20.1

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 (197) hide show
  1. package/build/cli/linux/linux.js +17 -6
  2. package/build/cli/linux/linux.js.map +1 -1
  3. package/build/cli/linux/runner-downloader.d.ts +0 -1
  4. package/build/cli/linux/runner-downloader.js +5 -11
  5. package/build/cli/linux/runner-downloader.js.map +1 -1
  6. package/build/cli/linux/runner-profiling.d.ts +6 -4
  7. package/build/cli/linux/runner-profiling.js +167 -37
  8. package/build/cli/linux/runner-profiling.js.map +1 -1
  9. package/build/cli/linux/runner.js +69 -56
  10. package/build/cli/linux/runner.js.map +1 -1
  11. package/build/library/sensors/gstreamer.d.ts +10 -3
  12. package/build/library/sensors/gstreamer.js +219 -52
  13. package/build/library/sensors/gstreamer.js.map +1 -1
  14. package/build/library/sensors/icamera.d.ts +21 -1
  15. package/build/library/sensors/imagesnap.d.ts +3 -2
  16. package/build/library/sensors/imagesnap.js +18 -1
  17. package/build/library/sensors/imagesnap.js.map +1 -1
  18. package/build/library/sensors/prophesee.d.ts +2 -2
  19. package/build/library/sensors/sensors-helper.d.ts +6 -1
  20. package/build/library/sensors/sensors-helper.js +32 -9
  21. package/build/library/sensors/sensors-helper.js.map +1 -1
  22. package/build/sdk/studio/sdk/api/adminApi.d.ts +4 -6
  23. package/build/sdk/studio/sdk/api/adminApi.js +4782 -4928
  24. package/build/sdk/studio/sdk/api/adminApi.js.map +1 -1
  25. package/build/sdk/studio/sdk/api/authApi.d.ts +4 -6
  26. package/build/sdk/studio/sdk/api/authApi.js +88 -56
  27. package/build/sdk/studio/sdk/api/authApi.js.map +1 -1
  28. package/build/sdk/studio/sdk/api/cDNApi.d.ts +4 -6
  29. package/build/sdk/studio/sdk/api/cDNApi.js +76 -53
  30. package/build/sdk/studio/sdk/api/cDNApi.js.map +1 -1
  31. package/build/sdk/studio/sdk/api/canaryApi.d.ts +4 -6
  32. package/build/sdk/studio/sdk/api/canaryApi.js +79 -53
  33. package/build/sdk/studio/sdk/api/canaryApi.js.map +1 -1
  34. package/build/sdk/studio/sdk/api/classifyApi.d.ts +4 -6
  35. package/build/sdk/studio/sdk/api/classifyApi.js +527 -499
  36. package/build/sdk/studio/sdk/api/classifyApi.js.map +1 -1
  37. package/build/sdk/studio/sdk/api/dSPApi.d.ts +4 -6
  38. package/build/sdk/studio/sdk/api/dSPApi.js +938 -942
  39. package/build/sdk/studio/sdk/api/dSPApi.js.map +1 -1
  40. package/build/sdk/studio/sdk/api/deploymentApi.d.ts +4 -6
  41. package/build/sdk/studio/sdk/api/deploymentApi.js +680 -603
  42. package/build/sdk/studio/sdk/api/deploymentApi.js.map +1 -1
  43. package/build/sdk/studio/sdk/api/devicesApi.d.ts +4 -6
  44. package/build/sdk/studio/sdk/api/devicesApi.js +802 -800
  45. package/build/sdk/studio/sdk/api/devicesApi.js.map +1 -1
  46. package/build/sdk/studio/sdk/api/emailVerificationApi.d.ts +4 -6
  47. package/build/sdk/studio/sdk/api/emailVerificationApi.js +184 -190
  48. package/build/sdk/studio/sdk/api/emailVerificationApi.js.map +1 -1
  49. package/build/sdk/studio/sdk/api/exportApi.d.ts +4 -6
  50. package/build/sdk/studio/sdk/api/exportApi.js +88 -56
  51. package/build/sdk/studio/sdk/api/exportApi.js.map +1 -1
  52. package/build/sdk/studio/sdk/api/featureFlagsApi.d.ts +4 -6
  53. package/build/sdk/studio/sdk/api/featureFlagsApi.js +76 -52
  54. package/build/sdk/studio/sdk/api/featureFlagsApi.js.map +1 -1
  55. package/build/sdk/studio/sdk/api/healthApi.d.ts +4 -6
  56. package/build/sdk/studio/sdk/api/healthApi.js +111 -97
  57. package/build/sdk/studio/sdk/api/healthApi.js.map +1 -1
  58. package/build/sdk/studio/sdk/api/impulseApi.d.ts +4 -6
  59. package/build/sdk/studio/sdk/api/impulseApi.js +942 -902
  60. package/build/sdk/studio/sdk/api/impulseApi.js.map +1 -1
  61. package/build/sdk/studio/sdk/api/integrationsApi.d.ts +4 -6
  62. package/build/sdk/studio/sdk/api/integrationsApi.js +136 -106
  63. package/build/sdk/studio/sdk/api/integrationsApi.js.map +1 -1
  64. package/build/sdk/studio/sdk/api/jobsApi.d.ts +4 -6
  65. package/build/sdk/studio/sdk/api/jobsApi.js +2270 -2326
  66. package/build/sdk/studio/sdk/api/jobsApi.js.map +1 -1
  67. package/build/sdk/studio/sdk/api/learnApi.d.ts +22 -6
  68. package/build/sdk/studio/sdk/api/learnApi.js +1597 -1424
  69. package/build/sdk/studio/sdk/api/learnApi.js.map +1 -1
  70. package/build/sdk/studio/sdk/api/loginApi.d.ts +4 -6
  71. package/build/sdk/studio/sdk/api/loginApi.js +112 -98
  72. package/build/sdk/studio/sdk/api/loginApi.js.map +1 -1
  73. package/build/sdk/studio/sdk/api/metricsApi.d.ts +4 -6
  74. package/build/sdk/studio/sdk/api/metricsApi.js +148 -144
  75. package/build/sdk/studio/sdk/api/metricsApi.js.map +1 -1
  76. package/build/sdk/studio/sdk/api/optimizationApi.d.ts +4 -6
  77. package/build/sdk/studio/sdk/api/optimizationApi.js +844 -844
  78. package/build/sdk/studio/sdk/api/optimizationApi.js.map +1 -1
  79. package/build/sdk/studio/sdk/api/organizationBlocksApi.d.ts +8 -6
  80. package/build/sdk/studio/sdk/api/organizationBlocksApi.js +1974 -1548
  81. package/build/sdk/studio/sdk/api/organizationBlocksApi.js.map +1 -1
  82. package/build/sdk/studio/sdk/api/organizationCreateProjectApi.d.ts +4 -6
  83. package/build/sdk/studio/sdk/api/organizationCreateProjectApi.js +700 -652
  84. package/build/sdk/studio/sdk/api/organizationCreateProjectApi.js.map +1 -1
  85. package/build/sdk/studio/sdk/api/organizationDataApi.d.ts +4 -6
  86. package/build/sdk/studio/sdk/api/organizationDataApi.js +2074 -1985
  87. package/build/sdk/studio/sdk/api/organizationDataApi.js.map +1 -1
  88. package/build/sdk/studio/sdk/api/organizationDataCampaignsApi.d.ts +4 -6
  89. package/build/sdk/studio/sdk/api/organizationDataCampaignsApi.js +626 -602
  90. package/build/sdk/studio/sdk/api/organizationDataCampaignsApi.js.map +1 -1
  91. package/build/sdk/studio/sdk/api/organizationJobsApi.d.ts +4 -6
  92. package/build/sdk/studio/sdk/api/organizationJobsApi.js +417 -399
  93. package/build/sdk/studio/sdk/api/organizationJobsApi.js.map +1 -1
  94. package/build/sdk/studio/sdk/api/organizationPipelinesApi.d.ts +4 -6
  95. package/build/sdk/studio/sdk/api/organizationPipelinesApi.js +419 -401
  96. package/build/sdk/studio/sdk/api/organizationPipelinesApi.js.map +1 -1
  97. package/build/sdk/studio/sdk/api/organizationPortalsApi.d.ts +4 -6
  98. package/build/sdk/studio/sdk/api/organizationPortalsApi.js +372 -352
  99. package/build/sdk/studio/sdk/api/organizationPortalsApi.js.map +1 -1
  100. package/build/sdk/studio/sdk/api/organizationsApi.d.ts +4 -6
  101. package/build/sdk/studio/sdk/api/organizationsApi.js +4024 -4050
  102. package/build/sdk/studio/sdk/api/organizationsApi.js.map +1 -1
  103. package/build/sdk/studio/sdk/api/performanceCalibrationApi.d.ts +4 -6
  104. package/build/sdk/studio/sdk/api/performanceCalibrationApi.js +586 -560
  105. package/build/sdk/studio/sdk/api/performanceCalibrationApi.js.map +1 -1
  106. package/build/sdk/studio/sdk/api/postProcessingApi.d.ts +4 -6
  107. package/build/sdk/studio/sdk/api/postProcessingApi.js +279 -255
  108. package/build/sdk/studio/sdk/api/postProcessingApi.js.map +1 -1
  109. package/build/sdk/studio/sdk/api/projectsApi.d.ts +4 -6
  110. package/build/sdk/studio/sdk/api/projectsApi.js +2758 -2818
  111. package/build/sdk/studio/sdk/api/projectsApi.js.map +1 -1
  112. package/build/sdk/studio/sdk/api/rawDataApi.d.ts +4 -6
  113. package/build/sdk/studio/sdk/api/rawDataApi.js +3055 -3131
  114. package/build/sdk/studio/sdk/api/rawDataApi.js.map +1 -1
  115. package/build/sdk/studio/sdk/api/testApi.d.ts +4 -6
  116. package/build/sdk/studio/sdk/api/testApi.js +152 -108
  117. package/build/sdk/studio/sdk/api/testApi.js.map +1 -1
  118. package/build/sdk/studio/sdk/api/themesApi.d.ts +4 -6
  119. package/build/sdk/studio/sdk/api/themesApi.js +341 -305
  120. package/build/sdk/studio/sdk/api/themesApi.js.map +1 -1
  121. package/build/sdk/studio/sdk/api/thirdPartyAuthApi.d.ts +4 -6
  122. package/build/sdk/studio/sdk/api/thirdPartyAuthApi.js +387 -353
  123. package/build/sdk/studio/sdk/api/thirdPartyAuthApi.js.map +1 -1
  124. package/build/sdk/studio/sdk/api/uploadPortalApi.d.ts +4 -6
  125. package/build/sdk/studio/sdk/api/uploadPortalApi.js +375 -355
  126. package/build/sdk/studio/sdk/api/uploadPortalApi.js.map +1 -1
  127. package/build/sdk/studio/sdk/api/userApi.d.ts +4 -6
  128. package/build/sdk/studio/sdk/api/userApi.js +2345 -2452
  129. package/build/sdk/studio/sdk/api/userApi.js.map +1 -1
  130. package/build/sdk/studio/sdk/api/vlmApi.d.ts +4 -6
  131. package/build/sdk/studio/sdk/api/vlmApi.js +277 -253
  132. package/build/sdk/studio/sdk/api/vlmApi.js.map +1 -1
  133. package/build/sdk/studio/sdk/api/whitelabelsApi.d.ts +4 -6
  134. package/build/sdk/studio/sdk/api/whitelabelsApi.js +408 -398
  135. package/build/sdk/studio/sdk/api/whitelabelsApi.js.map +1 -1
  136. package/build/sdk/studio/sdk/model/addOrganizationDeployBlockRequest.d.ts +4 -0
  137. package/build/sdk/studio/sdk/model/addOrganizationDeployBlockRequest.js +5 -0
  138. package/build/sdk/studio/sdk/model/addOrganizationDeployBlockRequest.js.map +1 -1
  139. package/build/sdk/studio/sdk/model/buildOnDeviceModelRequest.d.ts +6 -0
  140. package/build/sdk/studio/sdk/model/buildOnDeviceModelRequest.js +5 -0
  141. package/build/sdk/studio/sdk/model/buildOnDeviceModelRequest.js.map +1 -1
  142. package/build/sdk/studio/sdk/model/buildOrganizationOnDeviceModelRequest.d.ts +6 -0
  143. package/build/sdk/studio/sdk/model/buildOrganizationOnDeviceModelRequest.js +5 -0
  144. package/build/sdk/studio/sdk/model/buildOrganizationOnDeviceModelRequest.js.map +1 -1
  145. package/build/sdk/studio/sdk/model/deployPretrainedModelRequest.d.ts +4 -0
  146. package/build/sdk/studio/sdk/model/deployPretrainedModelRequest.js +5 -0
  147. package/build/sdk/studio/sdk/model/deployPretrainedModelRequest.js.map +1 -1
  148. package/build/sdk/studio/sdk/model/deploymentTarget.d.ts +2 -0
  149. package/build/sdk/studio/sdk/model/deploymentTarget.js +5 -0
  150. package/build/sdk/studio/sdk/model/deploymentTarget.js.map +1 -1
  151. package/build/sdk/studio/sdk/model/models.d.ts +47 -7
  152. package/build/sdk/studio/sdk/model/models.js +33 -22
  153. package/build/sdk/studio/sdk/model/models.js.map +1 -1
  154. package/build/sdk/studio/sdk/model/organizationDeployBlock.d.ts +9 -0
  155. package/build/sdk/studio/sdk/model/organizationDeployBlock.js +10 -0
  156. package/build/sdk/studio/sdk/model/organizationDeployBlock.js.map +1 -1
  157. package/build/sdk/studio/sdk/model/projectDeploymentTarget.d.ts +2 -0
  158. package/build/sdk/studio/sdk/model/projectDeploymentTarget.js +5 -0
  159. package/build/sdk/studio/sdk/model/projectDeploymentTarget.js.map +1 -1
  160. package/build/sdk/studio/sdk/model/transferLearningModel.d.ts +4 -0
  161. package/build/sdk/studio/sdk/model/transferLearningModel.js +5 -0
  162. package/build/sdk/studio/sdk/model/transferLearningModel.js.map +1 -1
  163. package/build/sdk/studio/sdk/model/updateOrganizationDeployBlockRequest.d.ts +4 -0
  164. package/build/sdk/studio/sdk/model/updateOrganizationDeployBlockRequest.js +5 -0
  165. package/build/sdk/studio/sdk/model/updateOrganizationDeployBlockRequest.js.map +1 -1
  166. package/build/sdk/studio/sdk/model/uploadPretrainedModelByUrlRequest.d.ts +47 -0
  167. package/build/sdk/studio/sdk/model/uploadPretrainedModelByUrlRequest.js +55 -0
  168. package/build/sdk/studio/sdk/model/uploadPretrainedModelByUrlRequest.js.map +1 -0
  169. package/build/sdk/studio/sdk/model/uploadPretrainedModelRequest.d.ts +4 -0
  170. package/build/sdk/studio/sdk/model/uploadPretrainedModelRequest.js +5 -0
  171. package/build/sdk/studio/sdk/model/uploadPretrainedModelRequest.js.map +1 -1
  172. package/package.json +4 -2
  173. package/test/gstreamer.test.ts +984 -3788
  174. package/test/imx219-csi-on-arduino-unoq-inspect.txt +564 -0
  175. package/test/imx219-csi-on-arduino-unoq-monitor.txt +285 -0
  176. package/test/logitech-c920-on-ubuntu-22-parallells.txt +211 -0
  177. package/test/logitech-c922-on-rpi-bullseye-2.txt +270 -0
  178. package/test/logitech-c922-on-rpi-bullseye.txt +331 -0
  179. package/test/macbook-pro-w-internal-and-external-cam-inspect.txt +1496 -0
  180. package/test/macbook-pro-w-internal-and-external-cam-monitor.txt +209 -0
  181. package/test/nvidia-jetson-w-csi-camera.txt +94 -0
  182. package/test/nvidia-jetson-w-logitech-c922-monitor.txt +204 -0
  183. package/test/nvidia-orin-w-basler-camera-inspect.txt +859 -0
  184. package/test/nvidia-orin-w-basler-camera-pylonsrc.txt +806 -0
  185. package/test/rb1-debian-inspect.txt +568 -0
  186. package/test/rb1-debian-libcamera-monitor.txt +190 -0
  187. package/test/rpi-cam-v3-c920-webcam-bookworm-no-libcamerasrc.txt +383 -0
  188. package/test/rpi4-trixie-csi-gst-device-monitor.txt +1110 -0
  189. package/test/rpi4-trixie-csi-gst-inspect.txt +1379 -0
  190. package/test/rpi5-with-csi-imx500-camera-monitor.txt +3617 -0
  191. package/test/rpi5-with-csi-imx708-monitor.txt +2277 -0
  192. package/test/usb-camera-on-rpi-w-image-jpg.txt +130 -0
  193. /package/test/{qualcomm-rb3-inspect-qtiqmmfsrc.txt → qualcomm-rb3-gen-2-qimp-linux-1-2-with-logitech-brio-inspect-qtiqmmfsrc.txt} +0 -0
  194. /package/test/{qualcomm-rb3-inspect.txt → qualcomm-rb3-gen-2-qimp-linux-1-2-with-logitech-brio-inspect.txt} +0 -0
  195. /package/test/{qualcomm-rb3-monitor-brio.txt → qualcomm-rb3-gen-2-qimp-linux-1-2-with-logitech-brio-monitor.txt} +0 -0
  196. /package/test/{triple-vision-camera-inspect.txt → triple-vision-ai-industrial-camera-inspect.txt} +0 -0
  197. /package/test/{triple-vision-camera-monitor.txt → triple-vision-ai-industrial-camera-monitor.txt} +0 -0
@@ -27,11 +27,15 @@ class GStreamer extends tsee_1.EventEmitter {
27
27
  this._isStarted = false;
28
28
  this._isRestarting = false;
29
29
  this._emitsOriginalSizeImages = false;
30
+ this._lastGstLaunchCommand = '';
31
+ this._imagesReceived = 0;
32
+ this._offset = 0;
30
33
  this._verbose = verbose;
31
34
  this._customLaunchCommand = options?.customLaunchCommand;
32
35
  this._spawnHelper = options?.spawnHelperOverride || spawn_helper_1.spawnHelper;
33
36
  this._modeOverride = options?.modeOverride;
34
37
  this._profiling = options?.profiling || false;
38
+ this._overrideColorFormat = options?.colorFormat;
35
39
  if (options?.dontRunCleanupLoop === true) {
36
40
  // skip cleanup loop
37
41
  }
@@ -57,31 +61,43 @@ class GStreamer extends tsee_1.EventEmitter {
57
61
  console.log(PREFIX, 'checking for /etc/os-release');
58
62
  osRelease = await fs_1.default.promises.readFile('/etc/os-release', 'utf-8');
59
63
  }
64
+ else {
65
+ // so we don't need to check for undefined below
66
+ osRelease = '';
67
+ }
60
68
  let firmwareModel;
61
69
  // using /proc/device-tree as recommended in user space.
62
70
  if (await this.exists('/proc/device-tree/model')) {
63
71
  firmwareModel = await fs_1.default.promises.readFile('/proc/device-tree/model', 'utf-8');
64
72
  }
65
- if (osRelease) {
66
- if ((osRelease.indexOf('bullseye') > -1)
67
- || (osRelease.indexOf('bookworm') > -1)) {
68
- if (osRelease.indexOf('ID=raspbian') > -1) {
69
- this._mode = 'rpi';
70
- }
71
- if (firmwareModel && firmwareModel.indexOf('Raspberry Pi') > -1) {
72
- this._mode = 'rpi';
73
- }
74
- }
75
- }
76
- if (firmwareModel && firmwareModel.indexOf('Microchip SAMA7G5') > -1) {
77
- this._mode = 'microchip';
73
+ else {
74
+ // so we don't need to check for undefined below
75
+ firmwareModel = '';
78
76
  }
79
- else if (firmwareModel && firmwareModel.indexOf('RB3gen2') > -1 && firmwareModel.indexOf('vision') > -1) {
77
+ if (firmwareModel.indexOf('RB3gen2') > -1 && firmwareModel.indexOf('vision') > -1) {
80
78
  this._mode = 'qualcomm-rb3gen2';
81
79
  }
82
- else if (firmwareModel && firmwareModel.indexOf('Qualcomm') > -1 && firmwareModel.indexOf('Yupik') > -1) {
80
+ else if (firmwareModel.indexOf('Qualcomm') > -1 && firmwareModel.indexOf('Yupik') > -1) {
83
81
  this._mode = 'qualcomm-yupik';
84
82
  }
83
+ else if (firmwareModel.indexOf('Raspberry Pi') > -1) {
84
+ if (((osRelease.indexOf('bullseye') > -1) || (osRelease.indexOf('bookworm') > -1))
85
+ && (osRelease.indexOf('ID=raspbian') === -1)) {
86
+ this._mode = 'rpi';
87
+ }
88
+ else if (osRelease.indexOf('trixie') > -1) {
89
+ this._mode = 'rpi';
90
+ }
91
+ // override to rpi5 if needed
92
+ if (firmwareModel.indexOf('Raspberry Pi 5') > -1) {
93
+ this._mode = 'rpi5';
94
+ }
95
+ }
96
+ else if ((firmwareModel.indexOf('Arduino') > -1 && firmwareModel.indexOf('Imola') > -1) ||
97
+ // this may be incorrect on the another platforms in the future
98
+ (process.env.EI_CLI_ENV === 'arduino')) {
99
+ this._mode = 'unoq';
100
+ }
85
101
  this._mode = (this._modeOverride) ? this._modeOverride : this._mode;
86
102
  }
87
103
  async listDevices() {
@@ -141,6 +157,8 @@ class GStreamer extends tsee_1.EventEmitter {
141
157
  args.push(`-v`);
142
158
  }
143
159
  args.push(pipeline);
160
+ // for logging purposes
161
+ this._lastGstLaunchCommand = `${command} ${args.join(' ')}`;
144
162
  if (this._verbose) {
145
163
  console.log(PREFIX, `Starting ${command} ${args.join(' ')}`);
146
164
  }
@@ -154,11 +172,77 @@ class GStreamer extends tsee_1.EventEmitter {
154
172
  if (this._verbose) {
155
173
  console.log(PREFIX, d.toString('utf-8'));
156
174
  }
157
- if (d.toString('utf-8').indexOf('frame_ready:sink') > -1) {
158
- this.emit('profilingInfo', new Date(), 'frame_ready');
159
- }
160
- if (d.toString('utf-8').indexOf('jpegenc_done:sink') > -1) {
161
- this.emit('profilingInfo', new Date(), 'jpegenc_done');
175
+ const ts = new Date();
176
+ const parsePtsFromLine = (line) => {
177
+ const m = line.match(/pts: ([\d\.\:]+)/);
178
+ if (m && m.length >= 2) {
179
+ return m[1];
180
+ }
181
+ return null;
182
+ };
183
+ const parseOffsetFromLine = (line) => {
184
+ const m = line.match(/offset: (-?[\d\.\:]+)/);
185
+ if (m && m.length >= 2) {
186
+ return Number(m[1]);
187
+ }
188
+ return null;
189
+ };
190
+ const str = d.toString('utf-8');
191
+ for (const line of str.split('\n')) {
192
+ if (line.trim().startsWith('/GstPipeline:pipeline0/GstIdentity:')) {
193
+ // identity elements
194
+ const pts = parsePtsFromLine(line);
195
+ let offset = parseOffsetFromLine(line);
196
+ const identity = line.replace('/GstPipeline:pipeline0/GstIdentity:', '').split(' ')[0]
197
+ .replace(':', '');
198
+ // no pts -> skip
199
+ if (!pts) {
200
+ continue;
201
+ }
202
+ // frame_ready w/o offset -> also skip
203
+ if (identity === 'frame_ready') {
204
+ if (offset === null) {
205
+ continue;
206
+ }
207
+ // e.g. qtiqmmfsrc always has offset -1 for frame_ready
208
+ if (offset === -1) {
209
+ offset = ++this._offset;
210
+ }
211
+ this.emit('profilingInfo', {
212
+ type: 'frame_ready',
213
+ ts: ts,
214
+ pts: pts,
215
+ offset: offset,
216
+ });
217
+ }
218
+ else {
219
+ this.emit('profilingInfo', {
220
+ type: 'event-without-filename',
221
+ ts: ts,
222
+ name: identity,
223
+ pts: pts,
224
+ });
225
+ }
226
+ }
227
+ else if (line.includes('GstMultiFileSink, filename=')) {
228
+ let filenameM = line.match(/filename=\(string\)([\w\.]+)/);
229
+ if (!filenameM || filenameM.length < 2) {
230
+ console.log(PREFIX, `Failed to parse filename from GstMultiFileSink: ` + line.trim());
231
+ continue;
232
+ }
233
+ let timestampM = line.match(/timestamp=\(guint64\)(\d+)/);
234
+ if (!timestampM || timestampM.length < 2) {
235
+ console.log(PREFIX, `Failed to parse timestamp from GstMultiFileSink: ` + line.trim());
236
+ continue;
237
+ }
238
+ let filename = filenameM[1];
239
+ let pts = this.timestampNsToPts(timestampM[1]);
240
+ this.emit('profilingInfo', {
241
+ type: 'pts-to-filename',
242
+ pts: pts,
243
+ filename: filename,
244
+ });
245
+ }
162
246
  }
163
247
  });
164
248
  this._captureProcess.stderr.on('data', (d) => {
@@ -185,6 +269,7 @@ class GStreamer extends tsee_1.EventEmitter {
185
269
  return;
186
270
  if (this._handledFiles[fileName])
187
271
  return;
272
+ this._imagesReceived++;
188
273
  // not next frame yet?
189
274
  if (this._processing || Date.now() < nextFrame) {
190
275
  this._handledFiles[fileName] = true;
@@ -226,11 +311,12 @@ class GStreamer extends tsee_1.EventEmitter {
226
311
  if (this._keepAliveTimeout) {
227
312
  clearTimeout(this._keepAliveTimeout);
228
313
  }
314
+ const tempDir = this._tempDir;
229
315
  try {
230
316
  let [imgBuffer, originalImgBuffer] = await Promise.all([
231
- fs_1.default.promises.readFile(path_1.default.join(this._tempDir, fileName)),
317
+ fs_1.default.promises.readFile(path_1.default.join(tempDir, fileName)),
232
318
  this._emitsOriginalSizeImages ?
233
- fs_1.default.promises.readFile(path_1.default.join(this._tempDir, originalName)) :
319
+ fs_1.default.promises.readFile(path_1.default.join(tempDir, originalName)) :
234
320
  null,
235
321
  ]);
236
322
  // hash not changed? don't emit another event (streamer does this on Rpi)
@@ -259,9 +345,8 @@ class GStreamer extends tsee_1.EventEmitter {
259
345
  };
260
346
  }
261
347
  catch (ex) {
262
- console.error(PREFIX, 'Failed to load file', path_1.default.join(this._tempDir, fileName), ex);
348
+ console.error(PREFIX, 'Failed to load file', path_1.default.join(tempDir, fileName), ex);
263
349
  }
264
- const tempDir = this._tempDir;
265
350
  await Promise.all([
266
351
  (async () => {
267
352
  await this.safeUnlinkFile(path_1.default.join(tempDir, fileName));
@@ -304,7 +389,13 @@ class GStreamer extends tsee_1.EventEmitter {
304
389
  return;
305
390
  }
306
391
  else {
307
- reject('Capture process failed with code ' + code);
392
+ if (this._imagesReceived === 0 && this._lastGstLaunchCommand) {
393
+ reject(`Capture process failed with code ${code}\n\n` +
394
+ `command: ${this._lastGstLaunchCommand}`);
395
+ }
396
+ else {
397
+ reject('Capture process failed with code ' + code);
398
+ }
308
399
  }
309
400
  }
310
401
  else {
@@ -358,15 +449,14 @@ class GStreamer extends tsee_1.EventEmitter {
358
449
  let customArgs = (0, argv_split_1.split)(this._customLaunchCommand);
359
450
  customArgs = customArgs.concat([
360
451
  `!`,
361
- `multifilesink`,
362
- `location=resized%05d.jpg`
452
+ `multifilesink location=resized%05d.jpg post-messages=true sync=false`,
363
453
  ]);
364
454
  return {
365
455
  command: 'gst-launch-1.0',
366
456
  pipeline: customArgs.join(' '),
367
457
  };
368
458
  }
369
- // now we need to determine the resolution... we want something as close as possible to dimensions.widthx480
459
+ // now we need to determine the resolution... we want something as close as possible to dimensions.
370
460
  let caps = device.caps.filter(c => {
371
461
  return c.width >= dimensions.width && c.height >= dimensions.height;
372
462
  }).sort((a, b) => {
@@ -389,24 +479,50 @@ class GStreamer extends tsee_1.EventEmitter {
389
479
  framerate: 30,
390
480
  };
391
481
  }
392
- let videoSource = [device.videoSource, 'device=' + device.id];
393
- if ((this._mode === 'rpi') || (this._mode === 'microchip')) {
394
- // Rpi camera
482
+ let videoSource = [];
483
+ if (this._profiling) {
484
+ videoSource.push('-m');
485
+ }
486
+ videoSource.push(device.videoSource);
487
+ if (device.id) {
488
+ videoSource.push(`device=${device.id}`);
489
+ }
490
+ if ((this._mode === 'rpi') || (this._mode === 'rpi5') || device.videoSource === 'libcamerasrc') {
491
+ // libcamera devices don't have id set (or have some unique on Raspberry Pi or Microchip)
395
492
  if ((!device.id)
396
493
  || (device.name.indexOf('unicam') > -1)
397
494
  || (device.name.indexOf('bcm2835-isp') > -1)) {
398
- videoSource = ['libcamerasrc'];
495
+ videoSource = [
496
+ ...(this._profiling ? ['-m'] : []),
497
+ 'libcamerasrc',
498
+ ...device.name ? ['camera-name="' + device.name + '"'] : [],
499
+ ];
399
500
  const hasPlugin = await this.hasGstPlugin('libcamerasrc');
400
501
  if (!hasPlugin) {
401
502
  throw new Error('Missing "libcamerasrc" gstreamer element. Install via `sudo apt install -y gstreamer1.0-libcamera`');
402
503
  }
403
504
  }
505
+ // FIXME: dirty hack for IPASoft on QRB2210
506
+ // Some resolutions reported by camera causes the pipeline to hang. To fix that, it seems
507
+ // we need to increase width and/or height by 8 pixels. This hack should be removed once
508
+ // the hardware driver for ISP on QRB2210 is released.
509
+ if (this._mode === 'unoq') {
510
+ cap.width += 8;
511
+ }
404
512
  }
405
513
  else if ((this._mode === 'qualcomm-rb3gen2') || (this._mode === 'qualcomm-yupik')) {
406
- videoSource = ['qtiqmmfsrc', 'name=camsrc', 'camera=' + device.id];
514
+ videoSource = [
515
+ ...(this._profiling ? ['-m'] : []),
516
+ 'qtiqmmfsrc',
517
+ 'name=camsrc',
518
+ 'camera=' + device.id,
519
+ ];
407
520
  }
408
521
  if (device.id === 'pylonsrc') {
409
- videoSource = ['pylonsrc'];
522
+ videoSource = [
523
+ ...(this._profiling ? ['-m'] : []),
524
+ 'pylonsrc',
525
+ ];
410
526
  }
411
527
  let cropArgs = [];
412
528
  if (inferenceDims) {
@@ -437,6 +553,23 @@ class GStreamer extends tsee_1.EventEmitter {
437
553
  `video/x-raw,width=${cap.width},height=${cap.height},format=YUY2`
438
554
  ]);
439
555
  }
556
+ else if (this._mode === 'rpi5') {
557
+ // on RPi 5 we need to set color format
558
+ let colorFormat = '';
559
+ if (this._overrideColorFormat) {
560
+ colorFormat = this._overrideColorFormat;
561
+ }
562
+ else if (cap.formats && cap.formats.indexOf('YUY2') > -1) {
563
+ colorFormat = 'YUY2';
564
+ }
565
+ else if (cap.formats) {
566
+ throw new Error('Detected RPi 5 camera. Please provide the color format with `--camera-color-format`, supported formats: ' + cap.formats.join(', '));
567
+ }
568
+ videoSource = videoSource.concat([
569
+ `!`,
570
+ `video/x-raw,width=${cap.width},height=${cap.height},format=${colorFormat}`
571
+ ]);
572
+ }
440
573
  else {
441
574
  videoSource = videoSource.concat([
442
575
  `!`,
@@ -454,12 +587,11 @@ class GStreamer extends tsee_1.EventEmitter {
454
587
  `jpegenc`,
455
588
  ...jpgencDoneArgs,
456
589
  `!`,
457
- `multifilesink`,
458
- `location=resized%05d.jpg`,
590
+ `multifilesink location=resized%05d.jpg post-messages=true sync=false`,
459
591
  ]);
460
592
  }
461
593
  else {
462
- let original = `t. ! queue ! jpegenc ! multifilesink location=original%05d.jpg`;
594
+ let original = `t. ! queue ! jpegenc ! multifilesink location=original%05d.jpg post-messages=true sync=false`;
463
595
  let resized = [
464
596
  `t. ! queue`,
465
597
  ...cropArgs,
@@ -467,8 +599,7 @@ class GStreamer extends tsee_1.EventEmitter {
467
599
  `jpegenc`,
468
600
  ...jpgencDoneArgs,
469
601
  `!`,
470
- `multifilesink`,
471
- `location=resized%05d.jpg`,
602
+ `multifilesink location=resized%05d.jpg post-messages=true sync=false`,
472
603
  ];
473
604
  args = videoSource.concat([
474
605
  ...frameReadyArgs,
@@ -487,15 +618,14 @@ class GStreamer extends tsee_1.EventEmitter {
487
618
  `!`,
488
619
  `image/jpeg,width=${cap.width},height=${cap.height}`,
489
620
  `!`,
490
- `multifilesink`,
491
- `location=resized%05d.jpg`
621
+ `multifilesink location=resized%05d.jpg post-messages=true sync=false`
492
622
  ]);
493
623
  }
494
624
  else if (cap.type === 'nvarguscamerasrc') {
495
625
  args = [
496
626
  `nvarguscamerasrc ! "video/x-raw(memory:NVMM),width=${cap.width},height=${cap.height}" ! ` +
497
627
  `nvvidconv flip-method=0 ! video/x-raw,width=${cap.width},height=${cap.height} ! nvvidconv ! ` +
498
- `jpegenc ! multifilesink location=resized%05d.jpg`
628
+ `jpegenc ! multifilesink location=resized%05d.jpg post-messages=true sync=false`
499
629
  ];
500
630
  }
501
631
  else {
@@ -604,7 +734,8 @@ class GStreamer extends tsee_1.EventEmitter {
604
734
  if (!currDevice)
605
735
  continue;
606
736
  if (l.startsWith('name :')) {
607
- currDevice.name = l.split(':')[1].trim();
737
+ // extract name from the l between 'name : ' and '\n', because name may contain colons as well
738
+ currDevice.name = l.split(':').slice(1).join(':').trim();
608
739
  continue;
609
740
  }
610
741
  if (l.startsWith('class :')) {
@@ -639,6 +770,12 @@ class GStreamer extends tsee_1.EventEmitter {
639
770
  if (currDevice.videoSource === 'pipewiresrc') {
640
771
  currDevice.videoSource = DEFAULT_GST_VIDEO_SOURCE;
641
772
  }
773
+ if (currDevice.videoSource === 'avfvideosrc') {
774
+ const m = l.match(/gst-launch-1.0 avfvideosrc device-index=(\d+) \!/);
775
+ if (m && m.length >= 2) {
776
+ currDevice.videoSource = `avfvideosrc device-index=${m[1]}`;
777
+ }
778
+ }
642
779
  }
643
780
  }
644
781
  }
@@ -650,6 +787,7 @@ class GStreamer extends tsee_1.EventEmitter {
650
787
  let width = (l.match(/width=[^\d]+(\d+)/) || [])[1];
651
788
  let height = (l.match(/height=[^\d]+(\d+)/) || [])[1];
652
789
  let framerate = (l.match(/framerate=[^\d]+(\d+)/) || [])[1];
790
+ let format = (l.match(/format=([a-zA-Z0-9]+)/) || [])[1];
653
791
  // Rpi on bullseye has lines like this..
654
792
  // eslint-disable-next-line @stylistic/max-len
655
793
  // 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 }
@@ -667,10 +805,11 @@ class GStreamer extends tsee_1.EventEmitter {
667
805
  width: Number(width || '0'),
668
806
  height: Number(height || '0'),
669
807
  framerate: Number(framerate || '0'),
808
+ formats: format ? [format] : []
670
809
  };
671
810
  return r;
672
811
  });
673
- if (this._mode === 'rpi' || this._mode === 'microchip') { // no framerate here...
812
+ if (this._mode === 'rpi' || this._mode === 'rpi5' || d.videoSource === 'libcamerasrc') { // no framerate here...
674
813
  c = c.filter(x => x.width && x.height);
675
814
  }
676
815
  else if (d.name === 'RZG2L_CRU') {
@@ -688,14 +827,23 @@ class GStreamer extends tsee_1.EventEmitter {
688
827
  else {
689
828
  c = c.filter(x => x.width && x.height && x.framerate);
690
829
  }
830
+ // get list of all formats form the c list
831
+ const uniqueFormats = Array.from(new Set(c.map(cap => cap.formats).flat()));
691
832
  c = c.reduce((curr, o) => {
692
- // deduplicate caps
693
- if (!curr.some(obj => obj.framerate === o.framerate &&
833
+ // deduplicate caps, prioritize 'video/x-raw' type
834
+ const existingIndex = curr.findIndex(obj => obj.framerate === o.framerate &&
694
835
  obj.width === o.width &&
695
- obj.height === o.height &&
696
- obj.framerate === o.framerate)) {
836
+ obj.height === o.height);
837
+ // store all supported formats (YUY2 etc.)
838
+ if (uniqueFormats) {
839
+ o.formats = uniqueFormats.filter((format) => format !== undefined);
840
+ }
841
+ if (existingIndex === -1) {
697
842
  curr.push(o);
698
843
  }
844
+ else if (o.type === 'video/x-raw' && curr[existingIndex].type !== 'video/x-raw') {
845
+ curr[existingIndex] = o;
846
+ }
699
847
  return curr;
700
848
  }, []);
701
849
  d.caps = c;
@@ -712,7 +860,7 @@ class GStreamer extends tsee_1.EventEmitter {
712
860
  // Qualcomm has their own plugin, query its too
713
861
  // because listQtiqmmsrc* returns hardcoded devices ONLY if a specific gst plugin
714
862
  // is available we need to detect device type before, as it may be RubikPi, RB3Gen2 or
715
- // any other with IMSDK loaded and unkniwn cameras
863
+ // any other with IMSDK loaded and unknown cameras
716
864
  if (this._mode === 'qualcomm-rb3gen2') {
717
865
  devices = devices.concat(await this.listQtiqmmsrcDevices());
718
866
  }
@@ -730,10 +878,18 @@ class GStreamer extends tsee_1.EventEmitter {
730
878
  videoSource: d.videoSource,
731
879
  };
732
880
  });
733
- // deduplicate (by id)
881
+ // deduplicate (by id if present, otherwise by name)
734
882
  mapped = mapped.reduce((curr, m) => {
735
- if (curr.find(x => x.id === m.id))
736
- return curr;
883
+ if (m.id) {
884
+ if (curr.find(x => x.id === m.id)) {
885
+ return curr;
886
+ }
887
+ }
888
+ else if (m.name) {
889
+ if (curr.find(x => x.name === m.name && !x.id)) {
890
+ return curr;
891
+ }
892
+ }
737
893
  curr.push(m);
738
894
  return curr;
739
895
  }, []);
@@ -1235,6 +1391,17 @@ class GStreamer extends tsee_1.EventEmitter {
1235
1391
  }
1236
1392
  }
1237
1393
  }
1394
+ timestampNsToPts(nsStr) {
1395
+ const ns = BigInt(nsStr); // important: avoid precision loss
1396
+ const HOUR = 3600000000000n;
1397
+ const MIN = 60000000000n;
1398
+ const SEC = 1000000000n;
1399
+ const h = ns / HOUR;
1400
+ const m = (ns / MIN) % 60n;
1401
+ const s = (ns / SEC) % 60n;
1402
+ const n = ns % SEC;
1403
+ return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}.${n.toString().padStart(9, '0')}`;
1404
+ }
1238
1405
  }
1239
1406
  exports.GStreamer = GStreamer;
1240
1407
  //# sourceMappingURL=gstreamer.js.map