Skip to content

Upgrade & fix GenTL multi-camera mode#76

Draft
C-Achard wants to merge 13 commits into
masterfrom
cy/gentl-cti-lock-fix
Draft

Upgrade & fix GenTL multi-camera mode#76
C-Achard wants to merge 13 commits into
masterfrom
cy/gentl-cti-lock-fix

Conversation

@C-Achard
Copy link
Copy Markdown
Contributor

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

  • Acquire the shared Harvester with SharedHarvesterPool.acquire(loaded).
  • Reuse the existing device_info_list from the shared Harvester.
  • Do not call Harvester.update() inside each open().
  • Protect shared Harvester ops with a shared entry lock.
  • Release the shared Harvester through SharedHarvesterPool.release(...) on close.

Other changes in brief

  • Adds a shared Harvester pool for GenTL device discovery
  • Small enhancements to GenTL for settings stability and debuggability
  • Updated tests
  • New debug log mode via CLI or env var

Automated summary

GenTL backend improvements

  • Added SharedHarvesterEntry and SharedHarvesterPool classes to gentl_discovery.py for 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)
  • Improved path normalization in _normalize_path to handle Windows case folding and canonicalization, ensuring consistent CTI file keys. (dlclivegui/cameras/backends/utils/gentl_discovery.py)

Multi-camera controller robustness

  • In SingleCameraWorker, now deep-copies CameraSettings to prevent side effects from shared references, and adds detailed debug logging before and after backend creation. (dlclivegui/services/multi_camera_controller.py) [1] [2]
  • Improved camera identity computation to use device serial numbers or device IDs when available, for more stable camera identification. Also, checks for duplicate camera configurations before starting. (dlclivegui/services/multi_camera_controller.py) [1] [2]
  • Ensured each camera worker receives its own settings copy, and logs camera startup with settings. (dlclivegui/services/multi_camera_controller.py)

Logging and configuration

  • Added a --debug-log CLI option and a configure_logging function to control application logging verbosity, with support for an environment variable override. (dlclivegui/main.py) [1] [2]

Test suite improvements

  • Introduced FakeSharedHarvesterPool and 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]
  • Updated test camera fetch logic to generate payloads dynamically if the queue is empty, better simulating real device behavior. (tests/cameras/backends/conftest.py)
  • Adjusted GenTL backend tests to reflect the new logic: serial device IDs are handled directly and do not trigger device enumeration or index rebinding. (tests/cameras/backends/test_gentl_backend.py) [1] [2]

C-Achard added 7 commits May 11, 2026 13:25
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.
@C-Achard C-Achard requested a review from Copilot May 26, 2026 10:09
@C-Achard C-Achard self-assigned this May 26, 2026
@C-Achard C-Achard added bug Something isn't working camera Related to cameras and camera backends config Related to user configs, oading, saving, etc labels May 26, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 calling Harvester.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.

Comment thread dlclivegui/cameras/backends/utils/gentl_discovery.py
Comment thread dlclivegui/services/multi_camera_controller.py
Comment thread tests/cameras/backends/conftest.py
@C-Achard C-Achard linked an issue May 26, 2026 that may be closed by this pull request
C-Achard added 3 commits May 26, 2026 14:14
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).
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread dlclivegui/cameras/backends/gentl_backend.py Outdated
Comment thread dlclivegui/cameras/backends/gentl_backend.py Outdated
C-Achard and others added 3 commits May 26, 2026 14:35
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working camera Related to cameras and camera backends config Related to user configs, oading, saving, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix multi-camera for GenTL backend

2 participants