@luxonis/depthai-viewer-common 3.9.7 → 4.0.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.
Files changed (154) hide show
  1. package/THIRD_PARTY_NOTICES.md +36 -304
  2. package/benchmark-cli.mjs +166 -11
  3. package/benchmark-lib.sh +40 -5
  4. package/benchmark-root.sh +79 -13
  5. package/benchmark.sh +112 -5
  6. package/dist/components/Streams.d.ts +6 -0
  7. package/dist/components/Streams.d.ts.map +1 -1
  8. package/dist/components/Streams.js +12 -4
  9. package/dist/components/Streams.js.map +1 -1
  10. package/dist/hooks/benchmark-automation.d.ts.map +1 -1
  11. package/dist/hooks/benchmark-automation.js +288 -63
  12. package/dist/hooks/benchmark-automation.js.map +1 -1
  13. package/dist/index.css +7 -0
  14. package/dist/utils/vite-dev-fix.d.ts.map +1 -1
  15. package/dist/utils/vite-dev-fix.js +0 -15
  16. package/dist/utils/vite-dev-fix.js.map +1 -1
  17. package/dist/visualizer/components/Panel.d.ts.map +1 -1
  18. package/dist/visualizer/components/Panel.js +6 -3
  19. package/dist/visualizer/components/Panel.js.map +1 -1
  20. package/dist/visualizer/components/shared-interval.d.ts +1 -1
  21. package/dist/visualizer/components/shared-interval.d.ts.map +1 -1
  22. package/dist/visualizer/components/shared-interval.js +6 -2
  23. package/dist/visualizer/components/shared-interval.js.map +1 -1
  24. package/dist/visualizer/connection/communicator.d.ts +1 -0
  25. package/dist/visualizer/connection/communicator.d.ts.map +1 -1
  26. package/dist/visualizer/connection/communicator.js.map +1 -1
  27. package/dist/visualizer/connection/connection.d.ts.map +1 -1
  28. package/dist/visualizer/connection/connection.js +8 -7
  29. package/dist/visualizer/connection/connection.js.map +1 -1
  30. package/dist/visualizer/connection/foxglove-connection.d.ts +4 -2
  31. package/dist/visualizer/connection/foxglove-connection.d.ts.map +1 -1
  32. package/dist/visualizer/connection/foxglove-connection.js +88 -40
  33. package/dist/visualizer/connection/foxglove-connection.js.map +1 -1
  34. package/dist/visualizer/context/MessagePipelineProvider.d.ts +1 -1
  35. package/dist/visualizer/context/MessagePipelineProvider.d.ts.map +1 -1
  36. package/dist/visualizer/context/MessagePipelineProvider.js +24 -6
  37. package/dist/visualizer/context/MessagePipelineProvider.js.map +1 -1
  38. package/dist/visualizer/context/VisualizerContext.d.ts.map +1 -1
  39. package/dist/visualizer/context/VisualizerContext.js +1 -32
  40. package/dist/visualizer/context/VisualizerContext.js.map +1 -1
  41. package/dist/visualizer/index.d.ts +1 -0
  42. package/dist/visualizer/index.d.ts.map +1 -1
  43. package/dist/visualizer/index.js +1 -0
  44. package/dist/visualizer/index.js.map +1 -1
  45. package/dist/visualizer/messaging/browser-decoder-fixtures.d.ts.map +1 -1
  46. package/dist/visualizer/messaging/browser-decoder-fixtures.js +187 -24
  47. package/dist/visualizer/messaging/browser-decoder-fixtures.js.map +1 -1
  48. package/dist/visualizer/messaging/decode-core.d.ts +9 -1
  49. package/dist/visualizer/messaging/decode-core.d.ts.map +1 -1
  50. package/dist/visualizer/messaging/decode-core.js +26 -16
  51. package/dist/visualizer/messaging/decode-core.js.map +1 -1
  52. package/dist/visualizer/messaging/decoder-fixtures.d.ts.map +1 -1
  53. package/dist/visualizer/messaging/decoder-fixtures.js +128 -1
  54. package/dist/visualizer/messaging/decoder-fixtures.js.map +1 -1
  55. package/dist/visualizer/messaging/decoder-harness.d.ts +2 -1
  56. package/dist/visualizer/messaging/decoder-harness.d.ts.map +1 -1
  57. package/dist/visualizer/messaging/decoder-harness.js.map +1 -1
  58. package/dist/visualizer/messaging/deserialization/pointcloud/pointcloudFromDepth.worker.d.ts +6 -1
  59. package/dist/visualizer/messaging/deserialization/pointcloud/pointcloudFromDepth.worker.d.ts.map +1 -1
  60. package/dist/visualizer/messaging/deserialization/pointcloud/pointcloudFromDepth.worker.js +5 -1
  61. package/dist/visualizer/messaging/deserialization/pointcloud/pointcloudFromDepth.worker.js.map +1 -1
  62. package/dist/visualizer/messaging/deserialization/pointcloud/poitcloudPoolManager.d.ts +10 -14
  63. package/dist/visualizer/messaging/deserialization/pointcloud/poitcloudPoolManager.d.ts.map +1 -1
  64. package/dist/visualizer/messaging/deserialization/pointcloud/poitcloudPoolManager.js +56 -288
  65. package/dist/visualizer/messaging/deserialization/pointcloud/poitcloudPoolManager.js.map +1 -1
  66. package/dist/visualizer/messaging/deserialization/pointcloud/utils.d.ts.map +1 -1
  67. package/dist/visualizer/messaging/deserialization/pointcloud/utils.js +2 -7
  68. package/dist/visualizer/messaging/deserialization/pointcloud/utils.js.map +1 -1
  69. package/dist/visualizer/messaging/deserialization/video/depth.d.ts +2 -1
  70. package/dist/visualizer/messaging/deserialization/video/depth.d.ts.map +1 -1
  71. package/dist/visualizer/messaging/deserialization/video/depth.js +9 -65
  72. package/dist/visualizer/messaging/deserialization/video/depth.js.map +1 -1
  73. package/dist/visualizer/messaging/deserialization/video/h264.d.ts +3 -3
  74. package/dist/visualizer/messaging/deserialization/video/h264.d.ts.map +1 -1
  75. package/dist/visualizer/messaging/deserialization/video/h264.js +80 -25
  76. package/dist/visualizer/messaging/deserialization/video/h264.js.map +1 -1
  77. package/dist/visualizer/messaging/deserialization/video/h265.d.ts +1 -1
  78. package/dist/visualizer/messaging/deserialization/video/h265.d.ts.map +1 -1
  79. package/dist/visualizer/messaging/deserialization/video/h265.js +62 -22
  80. package/dist/visualizer/messaging/deserialization/video/h265.js.map +1 -1
  81. package/dist/visualizer/messaging/deserialization/video/mjpeg.d.ts +1 -0
  82. package/dist/visualizer/messaging/deserialization/video/mjpeg.d.ts.map +1 -1
  83. package/dist/visualizer/messaging/deserialization/video/mjpeg.js +14 -2
  84. package/dist/visualizer/messaging/deserialization/video/mjpeg.js.map +1 -1
  85. package/dist/visualizer/messaging/deserialization/video/rgbd-to-pointcloud.d.ts +3 -1
  86. package/dist/visualizer/messaging/deserialization/video/rgbd-to-pointcloud.d.ts.map +1 -1
  87. package/dist/visualizer/messaging/deserialization/video/rgbd-to-pointcloud.js +152 -250
  88. package/dist/visualizer/messaging/deserialization/video/rgbd-to-pointcloud.js.map +1 -1
  89. package/dist/visualizer/messaging/deserialization.worker.d.ts +5 -3
  90. package/dist/visualizer/messaging/deserialization.worker.d.ts.map +1 -1
  91. package/dist/visualizer/messaging/deserialization.worker.js +16 -2
  92. package/dist/visualizer/messaging/deserialization.worker.js.map +1 -1
  93. package/dist/visualizer/messaging/message-event.d.ts +3 -0
  94. package/dist/visualizer/messaging/message-event.d.ts.map +1 -1
  95. package/dist/visualizer/messaging/message-event.js +18 -4
  96. package/dist/visualizer/messaging/message-event.js.map +1 -1
  97. package/dist/visualizer/messaging/message-handler.d.ts +3 -1
  98. package/dist/visualizer/messaging/message-handler.d.ts.map +1 -1
  99. package/dist/visualizer/messaging/message-handler.js +120 -49
  100. package/dist/visualizer/messaging/message-handler.js.map +1 -1
  101. package/dist/visualizer/output.css +7 -0
  102. package/dist/visualizer/panels/PointCloudPanel.d.ts.map +1 -1
  103. package/dist/visualizer/panels/PointCloudPanel.js +2 -0
  104. package/dist/visualizer/panels/PointCloudPanel.js.map +1 -1
  105. package/dist/visualizer/panels/image/ImageCanvasRenderer.d.ts.map +1 -1
  106. package/dist/visualizer/panels/image/ImageCanvasRenderer.js +246 -69
  107. package/dist/visualizer/panels/image/ImageCanvasRenderer.js.map +1 -1
  108. package/dist/visualizer/panels/image/annotation-overlay.d.ts.map +1 -1
  109. package/dist/visualizer/panels/image/annotation-overlay.js +16 -2
  110. package/dist/visualizer/panels/image/annotation-overlay.js.map +1 -1
  111. package/dist/visualizer/panels/image/raw-image-decoder.d.ts.map +1 -1
  112. package/dist/visualizer/panels/image/raw-image-decoder.js +1 -0
  113. package/dist/visualizer/panels/image/raw-image-decoder.js.map +1 -1
  114. package/dist/visualizer/panels/image/webgl-image-renderer.d.ts +11 -2
  115. package/dist/visualizer/panels/image/webgl-image-renderer.d.ts.map +1 -1
  116. package/dist/visualizer/panels/image/webgl-image-renderer.js +236 -41
  117. package/dist/visualizer/panels/image/webgl-image-renderer.js.map +1 -1
  118. package/dist/visualizer/panels/image/webgl-segmentation-mask-renderer.d.ts +16 -0
  119. package/dist/visualizer/panels/image/webgl-segmentation-mask-renderer.d.ts.map +1 -0
  120. package/dist/visualizer/panels/image/webgl-segmentation-mask-renderer.js +184 -0
  121. package/dist/visualizer/panels/image/webgl-segmentation-mask-renderer.js.map +1 -0
  122. package/dist/visualizer/panels/image/worker-image-decoder.d.ts.map +1 -1
  123. package/dist/visualizer/panels/image/worker-image-decoder.js +8 -3
  124. package/dist/visualizer/panels/image/worker-image-decoder.js.map +1 -1
  125. package/dist/visualizer/panels/pointcloud/PointCloudCanvasRenderer.d.ts.map +1 -1
  126. package/dist/visualizer/panels/pointcloud/PointCloudCanvasRenderer.js +256 -73
  127. package/dist/visualizer/panels/pointcloud/PointCloudCanvasRenderer.js.map +1 -1
  128. package/dist/visualizer/panels/pointcloud/point-cloud-materials.d.ts +5 -0
  129. package/dist/visualizer/panels/pointcloud/point-cloud-materials.d.ts.map +1 -0
  130. package/dist/visualizer/panels/pointcloud/point-cloud-materials.js +123 -0
  131. package/dist/visualizer/panels/pointcloud/point-cloud-materials.js.map +1 -0
  132. package/dist/visualizer/protobuf.generated/NNData.d.ts +92 -0
  133. package/dist/visualizer/protobuf.generated/NNData.d.ts.map +1 -0
  134. package/dist/visualizer/protobuf.generated/NNData.js +620 -0
  135. package/dist/visualizer/protobuf.generated/NNData.js.map +1 -0
  136. package/dist/visualizer/utils/benchmark-metrics.d.ts +27 -0
  137. package/dist/visualizer/utils/benchmark-metrics.d.ts.map +1 -0
  138. package/dist/visualizer/utils/benchmark-metrics.js +139 -0
  139. package/dist/visualizer/utils/benchmark-metrics.js.map +1 -0
  140. package/dist/visualizer/utils/comlink-wrap.d.ts.map +1 -1
  141. package/dist/visualizer/utils/comlink-wrap.js +5 -0
  142. package/dist/visualizer/utils/comlink-wrap.js.map +1 -1
  143. package/dist/visualizer/utils/poitcloud-sync.d.ts.map +1 -1
  144. package/dist/visualizer/utils/poitcloud-sync.js +5 -2
  145. package/dist/visualizer/utils/poitcloud-sync.js.map +1 -1
  146. package/package.json +3 -4
  147. package/dist/visualizer/messaging/deserialization/pointcloud/i420ToRgbaToPoitcloud.worker.d.ts +0 -2
  148. package/dist/visualizer/messaging/deserialization/pointcloud/i420ToRgbaToPoitcloud.worker.d.ts.map +0 -1
  149. package/dist/visualizer/messaging/deserialization/pointcloud/i420ToRgbaToPoitcloud.worker.js +0 -45
  150. package/dist/visualizer/messaging/deserialization/pointcloud/i420ToRgbaToPoitcloud.worker.js.map +0 -1
  151. package/dist/visualizer/messaging/deserialization/video/depth-coloring.worker.d.ts +0 -5
  152. package/dist/visualizer/messaging/deserialization/video/depth-coloring.worker.d.ts.map +0 -1
  153. package/dist/visualizer/messaging/deserialization/video/depth-coloring.worker.js +0 -124
  154. package/dist/visualizer/messaging/deserialization/video/depth-coloring.worker.js.map +0 -1
package/benchmark-cli.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import * as prompts from '@clack/prompts';
4
- import { spawn } from 'node:child_process';
5
- import { existsSync, statSync } from 'node:fs';
6
- import { dirname, join } from 'node:path';
4
+ import {spawn} from 'node:child_process';
5
+ import {existsSync, statSync} from 'node:fs';
6
+ import {dirname, join, resolve} from 'node:path';
7
7
  import process from 'node:process';
8
- import { clearLine, cursorTo } from 'node:readline';
9
- import { fileURLToPath } from 'node:url';
8
+ import {clearLine, cursorTo} from 'node:readline';
9
+ import {fileURLToPath} from 'node:url';
10
10
 
11
11
  const __filename = fileURLToPath(import.meta.url);
12
12
  const repoRoot = join(dirname(__filename), '..', '..');
@@ -16,11 +16,14 @@ const benchmarkCatalog = [
16
16
  { id: 'encoded-stream', label: 'H.264 Stream' },
17
17
  { id: 'nv12-stream', label: 'NV12 Stream' },
18
18
  { id: 'pointcloud', label: 'Point Cloud' },
19
+ { id: 'image-stream', label: 'Image Stream', optional: true },
19
20
  ];
20
21
  const backValue = '__back__';
21
22
  const customResolutionValue = '__custom_resolution__';
22
23
  const sourceResolutionValue = '__source_resolution__';
23
24
  const defaultResolution = process.env.BENCHMARK_RESOLUTION ?? '1920x1080';
25
+ const defaultFps = process.env.BENCHMARK_FPS ?? '30';
26
+ const defaultStreams = Number(process.env.BENCHMARK_STREAMS ?? 1);
24
27
  const progressEventPrefix = '__BENCHMARK_PROGRESS__|';
25
28
  const isWindows = process.platform === 'win32';
26
29
 
@@ -91,7 +94,11 @@ Commands:
91
94
  Options:
92
95
  --benchmark ID Select a single benchmark. Can be repeated.
93
96
  --benchmarks ID1,ID2 Select a comma-separated list of benchmarks.
97
+ --image PATH Stream one JPG, PNG, or other OpenCV-supported image.
98
+ --compressed Transport --image frames as H.264 instead of raw BGR888i.
94
99
  --resolution WIDTHxHEIGHT Resolution used by the run command.
100
+ --fps FPS|unpaced Publisher rate, default 30 FPS.
101
+ --streams N Number of concurrent stream topics, default 1.
95
102
  --interactive Force interactive benchmark selection.
96
103
  --no-interactive Disable interactive prompts.
97
104
  -h, --help Show this help message.
@@ -100,6 +107,8 @@ Examples:
100
107
  npm run benchmark
101
108
  npm run benchmark -- download
102
109
  npm run benchmark -- run --benchmark encoded-stream
110
+ npm run benchmark -- run --image ./odd-resolution.png
111
+ npm run benchmark -- run --image ./frame.png --compressed
103
112
  npm run benchmark -- list
104
113
  `);
105
114
  }
@@ -110,9 +119,13 @@ function parseArgs(argv) {
110
119
 
111
120
  const options = {
112
121
  benchmarkIds: [],
122
+ imagePath: null,
123
+ compressed: false,
113
124
  resolution: defaultResolution,
114
125
  hasResolutionFlag: false,
115
126
  interactive: null,
127
+ fps: defaultFps,
128
+ streams: defaultStreams,
116
129
  help: false,
117
130
  };
118
131
 
@@ -150,6 +163,33 @@ function parseArgs(argv) {
150
163
  options.hasResolutionFlag = true;
151
164
  break;
152
165
  }
166
+ case '--image': {
167
+ const value = args.shift();
168
+ if (!value) {
169
+ throw new Error('Missing value for --image');
170
+ }
171
+ options.imagePath = resolve(value);
172
+ break;
173
+ }
174
+ case '--compressed':
175
+ options.compressed = true;
176
+ break;
177
+ case '--fps': {
178
+ const value = args.shift();
179
+ if (!value) {
180
+ throw new Error('Missing value for --fps');
181
+ }
182
+ options.fps = value;
183
+ break;
184
+ }
185
+ case '--streams': {
186
+ const value = args.shift();
187
+ if (!value) {
188
+ throw new Error('Missing value for --streams');
189
+ }
190
+ options.streams = Number(value);
191
+ break;
192
+ }
153
193
  case '--interactive':
154
194
  options.interactive = true;
155
195
  break;
@@ -179,6 +219,9 @@ function parseArgs(argv) {
179
219
  }
180
220
 
181
221
  options.benchmarkIds = [...new Set(options.benchmarkIds)];
222
+ if (options.imagePath && options.benchmarkIds.length === 0) {
223
+ options.benchmarkIds = ['image-stream'];
224
+ }
182
225
  return { command, options };
183
226
  }
184
227
 
@@ -208,6 +251,15 @@ function validateResolution(resolution) {
208
251
  }
209
252
  }
210
253
 
254
+ function validateLoadOptions(fps, streams) {
255
+ if (fps !== 'unpaced' && (!Number.isFinite(Number(fps)) || Number(fps) <= 0)) {
256
+ throw new Error('FPS must be a positive number or unpaced');
257
+ }
258
+ if (!Number.isInteger(streams) || streams <= 0) {
259
+ throw new Error('Stream count must be a positive integer');
260
+ }
261
+ }
262
+
211
263
  function shouldPromptForAction(options, command) {
212
264
  if (options.interactive === false || command !== null) {
213
265
  return false;
@@ -224,6 +276,16 @@ function shouldPromptForBenchmarks(options) {
224
276
  return process.stdin.isTTY && process.stdout.isTTY;
225
277
  }
226
278
 
279
+ function validateImagePath(imagePath) {
280
+ if (!existsSync(imagePath)) {
281
+ throw new Error(`Image does not exist: ${imagePath}`);
282
+ }
283
+
284
+ if (!statSync(imagePath).isFile()) {
285
+ throw new Error(`Image path is not a file: ${imagePath}`);
286
+ }
287
+ }
288
+
227
289
  function shouldPromptForResolution(options, command) {
228
290
  if (command !== 'run') {
229
291
  return false;
@@ -236,6 +298,14 @@ function shouldPromptForResolution(options, command) {
236
298
  return process.stdin.isTTY && process.stdout.isTTY;
237
299
  }
238
300
 
301
+ function usesOnlyNativeImageResolution(options, benchmarkIds) {
302
+ return (
303
+ !options.hasResolutionFlag &&
304
+ benchmarkIds.length === 1 &&
305
+ benchmarkIds[0] === 'image-stream'
306
+ );
307
+ }
308
+
239
309
  function toSelectionArgs(benchmarkIds) {
240
310
  const args = [];
241
311
 
@@ -286,7 +356,9 @@ async function promptForBenchmarks() {
286
356
  }
287
357
 
288
358
  if (selectionMode === 'all') {
289
- return benchmarkCatalog.map((benchmark) => benchmark.id);
359
+ return benchmarkCatalog
360
+ .filter((benchmark) => !benchmark.optional)
361
+ .map((benchmark) => benchmark.id);
290
362
  }
291
363
 
292
364
  if (selectionMode === 'single') {
@@ -942,6 +1014,10 @@ async function resolveBenchmarkIds(options) {
942
1014
  }
943
1015
 
944
1016
  async function resolveRunResolution(options, command, benchmarkIds) {
1017
+ if (usesOnlyNativeImageResolution(options, benchmarkIds)) {
1018
+ return null;
1019
+ }
1020
+
945
1021
  if (!shouldPromptForResolution(options, command)) {
946
1022
  return options.resolution;
947
1023
  }
@@ -955,8 +1031,57 @@ async function resolveRunResolution(options, command, benchmarkIds) {
955
1031
  return selectedResolution;
956
1032
  }
957
1033
 
1034
+ async function resolveImagePath(options, command, benchmarkIds) {
1035
+ if (!benchmarkIds.includes('image-stream')) {
1036
+ if (options.imagePath) {
1037
+ throw new Error('--image requires the image-stream benchmark');
1038
+ }
1039
+ return null;
1040
+ }
1041
+
1042
+ if (command !== 'run') {
1043
+ return null;
1044
+ }
1045
+
1046
+ let imagePath = options.imagePath;
1047
+ if (!imagePath && options.interactive !== false && process.stdin.isTTY && process.stdout.isTTY) {
1048
+ const selectedImagePath = await prompts.text({
1049
+ message: 'Which image should be streamed?',
1050
+ placeholder: './image.png',
1051
+ validate: (value) => {
1052
+ try {
1053
+ validateImagePath(resolve(value));
1054
+ return;
1055
+ } catch (error) {
1056
+ return error instanceof Error ? error.message : String(error);
1057
+ }
1058
+ },
1059
+ });
1060
+
1061
+ if (prompts.isCancel(selectedImagePath)) {
1062
+ prompts.cancel('Image selection cancelled');
1063
+ process.exit(1);
1064
+ }
1065
+
1066
+ imagePath = resolve(selectedImagePath);
1067
+ }
1068
+
1069
+ if (!imagePath) {
1070
+ throw new Error('The image-stream benchmark requires --image PATH');
1071
+ }
1072
+
1073
+ validateImagePath(imagePath);
1074
+ return imagePath;
1075
+ }
1076
+
958
1077
  function formatResolutionDisplay(resolution, benchmarkIds) {
959
- return resolution === null ? 'recorded source resolution' : resolution;
1078
+ if (resolution !== null) {
1079
+ return resolution;
1080
+ }
1081
+
1082
+ return benchmarkIds.length === 1 && benchmarkIds[0] === 'image-stream'
1083
+ ? 'native image resolution'
1084
+ : 'recorded source resolution';
960
1085
  }
961
1086
 
962
1087
  function printBenchmarkList() {
@@ -1003,6 +1128,7 @@ async function main() {
1003
1128
  if (options.hasResolutionFlag) {
1004
1129
  validateResolution(options.resolution);
1005
1130
  }
1131
+ validateLoadOptions(options.fps, options.streams);
1006
1132
 
1007
1133
  for (;;) {
1008
1134
  if (shouldPromptForAction(options, command)) {
@@ -1027,10 +1153,15 @@ async function main() {
1027
1153
  }
1028
1154
 
1029
1155
  let benchmarkIds;
1156
+ let resolvedImagePath = null;
1030
1157
  let resolvedResolution = options.resolution;
1031
1158
  for (;;) {
1032
1159
  benchmarkIds = await resolveBenchmarkIds(options);
1033
1160
  if (benchmarkIds !== backValue) {
1161
+ resolvedImagePath = await resolveImagePath(options, command, benchmarkIds);
1162
+ if (options.compressed && resolvedImagePath === null) {
1163
+ throw new Error('--compressed requires the image-stream benchmark and --image PATH');
1164
+ }
1034
1165
  if (command !== 'run') {
1035
1166
  break;
1036
1167
  }
@@ -1063,11 +1194,25 @@ async function main() {
1063
1194
 
1064
1195
  const selectionArgs = toSelectionArgs(benchmarkIds);
1065
1196
  const resolutionArgs =
1066
- command === 'run' && resolvedResolution !== null
1067
- ? ['--resolution', resolvedResolution]
1197
+ command !== 'run'
1198
+ ? []
1199
+ : resolvedResolution === null
1200
+ ? ['--source-resolution']
1201
+ : ['--resolution', resolvedResolution];
1202
+ const imageArgs =
1203
+ command === 'run' && resolvedImagePath !== null
1204
+ ? ['--image', resolvedImagePath, ...(options.compressed ? ['--compressed'] : [])]
1205
+ : [];
1206
+ const loadArgs =
1207
+ command === 'run'
1208
+ ? ['--fps', String(options.fps), '--streams', String(options.streams)]
1068
1209
  : [];
1069
1210
  const selectedDisplay =
1070
- benchmarkIds.length > 0 ? benchmarkIds.join(', ') : 'all benchmarks';
1211
+ resolvedImagePath !== null
1212
+ ? `image-stream (${resolvedImagePath}${options.compressed ? ', H.264' : ', raw BGR888i'})`
1213
+ : benchmarkIds.length > 0
1214
+ ? benchmarkIds.join(', ')
1215
+ : 'all benchmarks';
1071
1216
  const resolutionDisplay =
1072
1217
  command === 'run' ? ` • ${formatResolutionDisplay(resolvedResolution, benchmarkIds)}` : '';
1073
1218
 
@@ -1093,11 +1238,21 @@ async function main() {
1093
1238
  prompts.outro('Starting benchmark flow');
1094
1239
  await runCommand(
1095
1240
  rootRunCommand[0],
1096
- [...rootRunCommand.slice(1), ...rootBenchmarkScript, ...selectionArgs, ...resolutionArgs],
1241
+ [
1242
+ ...rootRunCommand.slice(1),
1243
+ ...rootBenchmarkScript,
1244
+ ...selectionArgs,
1245
+ ...resolutionArgs,
1246
+ ...imageArgs,
1247
+ ...loadArgs,
1248
+ ],
1097
1249
  {
1098
1250
  env: {
1099
1251
  ...process.env,
1100
1252
  BENCHMARK_SKIP_DOWNLOAD: '1',
1253
+ BENCHMARK_FPS: String(options.fps),
1254
+ BENCHMARK_STREAMS: String(options.streams),
1255
+ BENCHMARK_RESOLUTION: resolvedResolution ?? 'source',
1101
1256
  },
1102
1257
  },
1103
1258
  );
package/benchmark-lib.sh CHANGED
@@ -7,6 +7,14 @@ BENCHMARK_DEFINITIONS=(
7
7
  "encoded-stream|H.264 Stream"
8
8
  "nv12-stream|NV12 Stream"
9
9
  "pointcloud|Point Cloud"
10
+ "image-stream|Image Stream"
11
+ )
12
+
13
+ BENCHMARK_DEFAULT_IDS=(
14
+ "bgr888i-stream"
15
+ "encoded-stream"
16
+ "nv12-stream"
17
+ "pointcloud"
10
18
  )
11
19
 
12
20
  BENCHMARK_ASSET_DEFINITIONS=(
@@ -278,20 +286,20 @@ benchmark_add_selected_csv() {
278
286
  }
279
287
 
280
288
  benchmark_select_all_if_empty() {
281
- local benchmark_definition benchmark_id
289
+ local benchmark_id
282
290
 
283
291
  if (( ${#BENCHMARK_SELECTED_IDS[@]} > 0 )); then
284
292
  return
285
293
  fi
286
294
 
287
- for benchmark_definition in "${BENCHMARK_DEFINITIONS[@]}"; do
288
- IFS='|' read -r benchmark_id _ <<<"${benchmark_definition}"
295
+ for benchmark_id in "${BENCHMARK_DEFAULT_IDS[@]}"; do
289
296
  BENCHMARK_SELECTED_IDS+=("${benchmark_id}")
290
297
  done
291
298
  }
292
299
 
293
300
  benchmark_parse_selection_flags() {
294
301
  BENCHMARK_SELECTED_IDS=()
302
+ local has_image=0
295
303
 
296
304
  while [[ $# -gt 0 ]]; do
297
305
  case "$1" in
@@ -311,23 +319,50 @@ benchmark_parse_selection_flags() {
311
319
  benchmark_add_selected_csv "$2" || return 1
312
320
  shift 2
313
321
  ;;
322
+ --image)
323
+ if [[ $# -lt 2 ]]; then
324
+ printf 'Missing value for --image\n' >&2
325
+ return 1
326
+ fi
327
+ has_image=1
328
+ shift 2
329
+ ;;
314
330
  *)
315
331
  shift
316
332
  ;;
317
333
  esac
318
334
  done
319
335
 
336
+ if (( has_image )) && (( ${#BENCHMARK_SELECTED_IDS[@]} == 0 )); then
337
+ BENCHMARK_SELECTED_IDS+=("image-stream")
338
+ elif (( has_image )) && ! benchmark_selection_contains "image-stream"; then
339
+ printf '%s\n' '--image requires the image-stream benchmark' >&2
340
+ return 1
341
+ fi
342
+
320
343
  benchmark_select_all_if_empty
321
344
  }
322
345
 
323
346
  benchmark_selected_plan_json() {
324
347
  local json='['
325
348
  local separator=''
326
- local benchmark_id topic_name
349
+ local benchmark_id topic_name topic_index required_topics
350
+ local stream_count="${BENCHMARK_STREAMS:-1}"
351
+ local target_fps="${BENCHMARK_FPS:-30}"
352
+ local resolution="${BENCHMARK_RESOLUTION:-source}"
327
353
 
328
354
  for benchmark_id in "${BENCHMARK_SELECTED_IDS[@]}"; do
329
355
  topic_name="$(benchmark_get_topic_name "${benchmark_id}")" || return 1
330
- json+="${separator}{\"id\":\"${benchmark_id}\",\"topicName\":\"${topic_name}\"}"
356
+ required_topics="[\"${topic_name}\""
357
+ for ((topic_index = 2; topic_index <= stream_count; topic_index += 1)); do
358
+ required_topics+=",\"${topic_name} #${topic_index}\""
359
+ done
360
+ required_topics+=']'
361
+ if [[ "${target_fps}" == 'unpaced' ]]; then
362
+ json+="${separator}{\"id\":\"${benchmark_id}\",\"topicName\":\"${topic_name}\",\"streamCount\":${stream_count},\"targetFps\":\"unpaced\",\"resolution\":\"${resolution}\",\"requiredTopics\":${required_topics}}"
363
+ else
364
+ json+="${separator}{\"id\":\"${benchmark_id}\",\"topicName\":\"${topic_name}\",\"streamCount\":${stream_count},\"targetFps\":${target_fps},\"resolution\":\"${resolution}\",\"requiredTopics\":${required_topics}}"
365
+ fi
331
366
  separator=','
332
367
  done
333
368
 
package/benchmark-root.sh CHANGED
@@ -14,6 +14,9 @@ benchmark_init_ui
14
14
  REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
15
15
  VISUALIZER_DIR="${REPO_ROOT}/packages/visualizer"
16
16
  VITE_BIN="${REPO_ROOT}/node_modules/.bin/vite"
17
+ read -r BENCHMARK_VISUALIZER_HOST BENCHMARK_VISUALIZER_PORT < <(
18
+ node -e 'const url = new URL(process.argv[1]); console.log(url.hostname, url.port || (url.protocol === "https:" ? "443" : "80"))' "${BENCHMARK_VISUALIZER_URL}"
19
+ )
17
20
 
18
21
  configure_windows_npm_script_shell() {
19
22
  if [[ "${OSTYPE:-}" != msys* && "${OSTYPE:-}" != cygwin* ]]; then
@@ -50,7 +53,33 @@ if ! benchmark_parse_selection_flags "$@"; then
50
53
  exit 1
51
54
  fi
52
55
 
56
+ benchmark_root_args=("$@")
57
+ for ((benchmark_arg_index = 0; benchmark_arg_index < ${#benchmark_root_args[@]}; benchmark_arg_index += 1)); do
58
+ case "${benchmark_root_args[benchmark_arg_index]}" in
59
+ --fps)
60
+ BENCHMARK_FPS="${benchmark_root_args[benchmark_arg_index + 1]}"
61
+ ;;
62
+ --streams)
63
+ BENCHMARK_STREAMS="${benchmark_root_args[benchmark_arg_index + 1]}"
64
+ ;;
65
+ --resolution)
66
+ BENCHMARK_RESOLUTION="${benchmark_root_args[benchmark_arg_index + 1]}"
67
+ ;;
68
+ --source-resolution)
69
+ BENCHMARK_RESOLUTION='source'
70
+ ;;
71
+ esac
72
+ done
73
+ export BENCHMARK_FPS="${BENCHMARK_FPS:-30}"
74
+ export BENCHMARK_STREAMS="${BENCHMARK_STREAMS:-1}"
75
+ export BENCHMARK_RESOLUTION="${BENCHMARK_RESOLUTION:-source}"
76
+
53
77
  benchmark_plan="$(benchmark_selected_plan_json)"
78
+ BENCHMARK_HARDWARE="$({
79
+ cd "${REPO_ROOT}"
80
+ node --input-type=module -e "import { collectHardwareReport } from './tools/benchmark-weekly/benchmark-report.mjs'; process.stdout.write(JSON.stringify(collectHardwareReport('/tmp')));"
81
+ })"
82
+ export BENCHMARK_HARDWARE
54
83
 
55
84
  cleanup() {
56
85
  if [[ -f "${BENCHMARK_VISUALIZER_PIDFILE}" ]]; then
@@ -119,16 +148,57 @@ open_visualizer_preview() {
119
148
  trap cleanup EXIT HUP INT QUIT TERM
120
149
  cleanup
121
150
 
151
+ configured_visualizer_port="${BENCHMARK_VISUALIZER_PORT}"
152
+ BENCHMARK_VISUALIZER_PORT="$(
153
+ node -e '
154
+ const net = require("node:net");
155
+ const host = process.argv[1];
156
+ const firstPort = Number(process.argv[2]);
157
+ const lastPort = firstPort + 100;
158
+ const findAvailablePort = (port) => {
159
+ if (port > lastPort) {
160
+ console.error(`No free benchmark preview port found between ${firstPort} and ${lastPort}.`);
161
+ process.exit(1);
162
+ }
163
+ const server = net.createServer();
164
+ server.unref();
165
+ server.once("error", (error) => {
166
+ if (error.code === "EADDRINUSE" || error.code === "EACCES") {
167
+ findAvailablePort(port + 1);
168
+ return;
169
+ }
170
+ throw error;
171
+ });
172
+ server.listen({ host, port }, () => server.close(() => console.log(port)));
173
+ };
174
+ findAvailablePort(firstPort);
175
+ ' "${BENCHMARK_VISUALIZER_HOST}" "${configured_visualizer_port}"
176
+ )"
177
+ if [[ "${BENCHMARK_VISUALIZER_PORT}" != "${configured_visualizer_port}" ]]; then
178
+ BENCHMARK_VISUALIZER_URL="$(
179
+ node -e 'const url = new URL(process.argv[1]); url.port = process.argv[2]; console.log(url.href)' \
180
+ "${BENCHMARK_VISUALIZER_URL}" "${BENCHMARK_VISUALIZER_PORT}"
181
+ )"
182
+ benchmark_log warn "Port ${configured_visualizer_port} is occupied; using ${BENCHMARK_VISUALIZER_URL}"
183
+ fi
184
+
185
+ benchmark_log info "Visualizer plan: $(benchmark_selected_ids_display)"
122
186
  (
123
187
  cd "${VISUALIZER_DIR}"
124
- benchmark_log info "Visualizer plan: $(benchmark_selected_ids_display)"
125
- BENCHMARK=true BENCHMARK_PLAN="${benchmark_plan}" npm run build
126
- # `open_visualizer_preview` owns browser launching so we can avoid duplicate tabs
127
- # and still respect `BENCHMARK_OPEN_BROWSER=0`.
128
- BENCHMARK=true BENCHMARK_PLAN="${benchmark_plan}" "${VITE_BIN}" preview --host localhost
129
- ) >"${BENCHMARK_VISUALIZER_LOG}" 2>&1 &
188
+ BENCHMARK=true BENCHMARK_PLAN="${benchmark_plan}" BENCHMARK_HARDWARE="${BENCHMARK_HARDWARE}" npm run build
189
+ ) >"${BENCHMARK_VISUALIZER_LOG}" 2>&1
190
+
191
+ # Replace the background shell with Vite so the PID file tracks the server
192
+ # itself. Otherwise the shell can exit first and leave an orphaned preview.
193
+ (
194
+ cd "${VISUALIZER_DIR}"
195
+ exec env BENCHMARK=true BENCHMARK_PLAN="${benchmark_plan}" BENCHMARK_HARDWARE="${BENCHMARK_HARDWARE}" "${VITE_BIN}" preview \
196
+ --host "${BENCHMARK_VISUALIZER_HOST}" \
197
+ --port "${BENCHMARK_VISUALIZER_PORT}" \
198
+ --strictPort
199
+ ) >>"${BENCHMARK_VISUALIZER_LOG}" 2>&1 &
130
200
  visualizer_pid=$!
131
- printf '%s' "${visualizer_pid}" >"${BENCHMARK_VISUALIZER_PIDFILE}"
201
+ printf '%s\n' "${visualizer_pid}" >"${BENCHMARK_VISUALIZER_PIDFILE}"
132
202
 
133
203
  benchmark_log info "Starting visualizer preview. Logs: ${BENCHMARK_VISUALIZER_LOG}"
134
204
  for _ in {1..120}; do
@@ -137,18 +207,14 @@ for _ in {1..120}; do
137
207
  exit 1
138
208
  fi
139
209
 
140
- if curl -sf http://localhost:4173/ >/dev/null; then
141
- listener_pid="$(lsof -tiTCP:4173 -sTCP:LISTEN 2>/dev/null | head -n 1 || true)"
142
- if [[ -n "${listener_pid}" ]] && ! grep -qx "${listener_pid}" "${BENCHMARK_VISUALIZER_PIDFILE}"; then
143
- printf '\n%s' "${listener_pid}" >>"${BENCHMARK_VISUALIZER_PIDFILE}"
144
- fi
210
+ if curl -sf "${BENCHMARK_VISUALIZER_URL}" >/dev/null; then
145
211
  break
146
212
  fi
147
213
 
148
214
  sleep 1
149
215
  done
150
216
 
151
- if ! curl -sf http://localhost:4173/ >/dev/null; then
217
+ if ! curl -sf "${BENCHMARK_VISUALIZER_URL}" >/dev/null; then
152
218
  benchmark_log error "Visualizer preview did not become ready. See ${BENCHMARK_VISUALIZER_LOG}"
153
219
  exit 1
154
220
  fi