Upgrade & fix GenTL multi-camera mode#76
Draft
C-Achard wants to merge 13 commits into
Draft
Conversation
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.
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.
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.
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.
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.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates the GenTL backend to support reliable multi-camera startup by introducing a process-local shared-Harvester model (keyed by canonicalized CTI file sets), and expands tests and logging to validate and debug the new behavior.
Changes:
- Added a shared Harvester pool (
SharedHarvesterEntry/SharedHarvesterPool) and path canonicalization to avoid per-camera Harvester enumeration conflicts. - Updated
GenTLCameraBackend.open()to acquire/reuse shared Harvester instances and avoid callingHarvester.update()per camera. - Improved multi-camera controller stability (settings deep-copies, duplicate detection) and added tests + a new debug logging flag.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
dlclivegui/cameras/backends/utils/gentl_discovery.py |
Adds shared Harvester pooling and path normalization for CTI-based sharing. |
dlclivegui/cameras/backends/gentl_backend.py |
Switches GenTL open/close to shared-Harvester lifecycle; adds selection/config/telemetry updates. |
dlclivegui/services/multi_camera_controller.py |
Deep-copies settings per worker and adds duplicate camera configuration detection + logging. |
dlclivegui/main.py |
Adds --debug-log and env override to control logging verbosity. |
tests/cameras/backends/conftest.py |
Adds Fake shared pool + updates fake acquisition behavior and SDK patching for pooled Harvester. |
tests/cameras/backends/test_gentl_backend.py |
Updates/extends tests for serial-ID rebinding behavior and shared Harvester reuse. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
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.
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).
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Scope
This PR fixes multi-camera startup for GenTL cameras by replacing the per-camera Harvester() with a shared-Harvester model.
Once the first Imaging Source USB3 Vision camera is opened/streaming, a second independent Harvester() instance can no longer reliably enumerate devices.
Key behavior
Other changes in brief
Automated summary
GenTL backend improvements
SharedHarvesterEntryandSharedHarvesterPoolclasses togentl_discovery.pyfor process-local sharing and reference counting of Harvester instances, keyed by canonicalized CTI file sets. Prevents first Harvester from keeping all cti to itself and making second instance see none. (dlclivegui/cameras/backends/utils/gentl_discovery.py)_normalize_pathto handle Windows case folding and canonicalization, ensuring consistent CTI file keys. (dlclivegui/cameras/backends/utils/gentl_discovery.py)Multi-camera controller robustness
SingleCameraWorker, now deep-copiesCameraSettingsto prevent side effects from shared references, and adds detailed debug logging before and after backend creation. (dlclivegui/services/multi_camera_controller.py) [1] [2]dlclivegui/services/multi_camera_controller.py) [1] [2]dlclivegui/services/multi_camera_controller.py)Logging and configuration
--debug-logCLI option and aconfigure_loggingfunction to control application logging verbosity, with support for an environment variable override. (dlclivegui/main.py) [1] [2]Test suite improvements
FakeSharedHarvesterPooland related helpers to simulate the shared Harvester pool in tests, ensuring the test environment matches production pooling and reference counting behavior. (tests/cameras/backends/conftest.py) [1] [2]tests/cameras/backends/conftest.py)tests/cameras/backends/test_gentl_backend.py) [1] [2]