Repository navigation
Commit 36a3d56
Upgrade & fix GenTL multi-camera mode (#76)
* Add shared Harvester pool and path normalization
Introduce thread-safe SharedHarvesterEntry and SharedHarvesterPool to share Harvester instances keyed by canonical CTI file sets. The pool provides acquire/release/refcount/refresh semantics with RLock protection, reference counting, initial device enumeration, and safe reset on final release. Add optional import handling for harvesters (raising a clear error when missing). Enhance _normalize_path with a casefold_windows flag to produce a canonical path form for pool keys (used when sorting/canonicalizing CTI file lists) and import threading to support locking.
* Use shared Harvester pool for GenTL producers
Introduce a process-shared Harvester (SharedHarvesterPool) and per-backend _shared_entry to manage GenTL producer state and locking. CTI preflight now records CTIs that passed validation and acquires a shared Harvester instance; device list refresh and acquirer creation/start/stop/destroy are performed under the shared lock to avoid race conditions/hotplug issues. On acquire failure the shared entry is released and a descriptive RuntimeError is raised. _reset_harvester now releases the shared entry when present. Minor diagnostics updates: persist CTI lists and adjust reporting of loaded CTIs.
* WIP Working multi CTI implementation
* Clean up file
* Handle GenTL open errors & improve device matching
Wrap harvester acquisition and camera initialization in a try/except to ensure resources are cleaned up on failure and to raise a clearer RuntimeError that includes loaded/failed CTIs and the original exception. Improve device selection logic: when a target_device_id or explicit serial is provided but not found, raise a descriptive error listing available serials; otherwise keep index-based selection and validate index range.
* Improve GenTL pixel format selection and conversion
Add explicit lists of color and mono GenTL pixel formats and default pixel_format to "auto" with normalization. Rewrite _configure_pixel_format to handle missing PixelFormat node, choose a suitable format when "auto" is requested (prefer color formats, then mono, then first available), warn and fallback when a requested format is unavailable, and persist the selected format. Update frame postprocessing to use the normalized pixel format for proper Bayer demosaicing (BayerRG/GB/GR/BG) and correct RGB->BGR conversion while leaving BGR8 native. Minor logging message tweaks and added defensive checks to improve robustness.
* Expose shared GenTL harvester diagnostics
Capture and surface CTI load diagnostics when acquiring the shared GenTL Harvester: record loaded and failed CTI files from the shared entry and from acquire-time exceptions, and slightly reformat the open() error message. Add a FakeSharedHarvesterPool test double (with FakeSharedEntry and custom acquire/release/refcount behavior) and integrate it into the test fixture patch_gentl_sdk so tests can exercise shared-harvester reuse, update counting and failure release semantics. Also adjust FakeImageAcquirer to clear its queue on start and to synthesize payloads when the queue is empty, wrap FakeHarvester.update to track update calls, and update tests to reflect new rebind/open behavior and to add coverage for shared harvester reuse and error propagation.
* Handle CTI load failures and track failed files
Treat failed CTI loads as a mapping of CTI->error and record failures when initializing the shared Harvester. gentl_discovery.py now logs exceptions, captures failed_files as a dict, and raises a runtime error if no CTI producers were successfully loaded; it also attaches loaded_files and failed_files to raised exceptions and attempts to reset the harvester. gentl_backend.py updated to consume failed_files as a dict (using .items()) when building reporting data. Added a helper to reset the harvester and propagate context for callers.
* Improve duplicate camera detection and reporting
Change seen from a set to a mapping of identity key -> camera_id to record which camera produced each key. Add get_camera_id and fallback to camera_id if camera_identity_key raises, logging the exception. Emit a more informative initialization_failed message that includes the camera_id and the conflicting camera, improving diagnostics and robustness when computing identity keys.
* Sort file paths in FakeSharedHarvesterPool._key
Make the pool key order-independent by sorting normalized absolute file paths before forming the tuple. This prevents different keys for the same set of CTI files when they are provided in a different order (while preserving normcase/abspath normalization).
* Merge failed CTI files instead of overwrite
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Avoid overwriting failed CTIs
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* pre-commit
* Revert display name change
* Use get_display_id in multicam test
Update tests/services/test_multicam_controller.py to import and use get_display_id instead of get_camera_id when accessing mfd.frames. This aligns the test with the frames dict keys (display IDs) and the updated multi_camera_controller API.
* Propagate display IDs for camera labeling
Add support for display_id labels throughout the multi-camera flow. MultiFrameData now includes display_ids; MultiCameraController stores per-camera display_ids (set on start, cleared on stop/reset) and emits them with frame_ready. Also switch to getting camera_id and display_id separately when starting workers. The tiled-frame helper create_tiled_frame gained an optional labels mapping and will draw the display label (falling back to camera_id) on each tile so the GUI can show friendly names.
* Support fp: targets and downgrade CTI error log
Treat target IDs starting with "fp:" as valid and return settings early so open() can match devices by fingerprint via existing _select_device/_match_device logic. Also change CTI file load failures from logger.exception to logger.warning to reduce noisy stack traces while still recording failed files for diagnostics.
* Add tests for stable camera ID usage
Add unit tests to ensure services use stable camera IDs (get_camera_id) rather than GUI display IDs (get_display_id). Tests added to tests/gui/test_rec_manager.py verify RecordingManager routes frames by stable ID, doesn't accept frames keyed by display ID, and doesn't infer frame size from display-only keys. Tests added/updated in tests/services/test_multicam_controller.py assert MultiCameraController emits frames and timestamps keyed by stable IDs, exposes a display_id mapping, and no internal use of display IDs; also update an existing rotation test to reference the stable camera ID. Imported get_camera_id/get_display_id and CameraSettings where needed.
* Restore clean up of stopped camera threads before restart
When starting a camera, the controller again detects stale worker entries whose thread is missing or no longer running, logs a warning, and cleans up that camera state before continuing.
* Improve consistency in camera identity fallback logic
Update `camera_identity_key` to better preserve camera identity across sessions. The backend namespace lookup is now guarded to avoid non-dict values, `device_id` is normalized to string, and serial-based identifiers (`serial_number`, `device_serial_number`, `serial`) are used before falling back to index.
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>1 parent 5cdaa09 commit 36a3d56
10 files changed
Lines changed: 1589 additions & 1164 deletions
File tree
- dlclivegui
- cameras
- backends
- utils
- services
- utils
- tests
- cameras/backends
- gui
- services
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
| 10 | + | |
9 | 11 | | |
10 | 12 | | |
11 | 13 | | |
| |||
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
21 | 142 | | |
22 | 143 | | |
23 | 144 | | |
| |||
81 | 202 | | |
82 | 203 | | |
83 | 204 | | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
| 205 | + | |
90 | 206 | | |
91 | 207 | | |
92 | 208 | | |
93 | | - | |
| 209 | + | |
94 | 210 | | |
95 | | - | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
96 | 217 | | |
97 | 218 | | |
98 | 219 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
454 | 454 | | |
455 | 455 | | |
456 | 456 | | |
457 | | - | |
458 | | - | |
| 457 | + | |
459 | 458 | | |
460 | | - | |
| 459 | + | |
461 | 460 | | |
462 | | - | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
463 | 467 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
54 | 55 | | |
55 | 56 | | |
56 | 57 | | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
57 | 84 | | |
58 | 85 | | |
59 | 86 | | |
| |||
77 | 104 | | |
78 | 105 | | |
79 | 106 | | |
| 107 | + | |
80 | 108 | | |
81 | 109 | | |
82 | 110 | | |
83 | 111 | | |
84 | 112 | | |
85 | | - | |
| 113 | + | |
86 | 114 | | |
87 | 115 | | |
88 | 116 | | |
| |||
0 commit comments