Skip to content

Commit 2332c3f

Browse files
committed
Reduce lock scope and refactor frame handling
Refactor _on_frame_captured to minimize time spent under _frame_lock and improve timing granularity. Introduces a frame_data local, renames timing labels (e.g. Multi.apply_transforms, Multi.store_latest, Multi.build_ordered, Multi.construct_frame_data), and moves frame_data construction inside measured blocks. The frame_ready emit is now performed outside the lock and guarded by a None check to avoid holding the lock during signal emission. Also small whitespace and cleanup changes.
1 parent f201917 commit 2332c3f

1 file changed

Lines changed: 35 additions & 30 deletions

File tree

dlclivegui/services/multi_camera_controller.py

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -389,51 +389,56 @@ def stop(self, wait: bool = True) -> None:
389389

390390
def _on_frame_captured(self, camera_id: str, frame: np.ndarray, timestamp: float) -> None:
391391
"""Handle a frame from one camera."""
392-
# Apply rotation if configured
393392
timing = self._timing_for_camera(camera_id)
393+
frame_data: MultiFrameData | None = None
394394

395395
with timing.measure("Multi.slot.total"):
396396
settings = self._settings.get(camera_id)
397-
with timing.measure("Multi.slot.apply_transforms"):
397+
398+
with timing.measure("Multi.apply_transforms"):
398399
if settings and settings.rotation:
399400
frame = MultiCameraController.apply_rotation(frame, settings.rotation)
400401

401-
# Apply cropping if configured
402402
if settings:
403403
crop_region = settings.get_crop_region()
404404
if crop_region:
405405
frame = MultiCameraController.apply_crop(frame, crop_region)
406-
with timing.measure("Multi.update_latest"):
407-
with self._frame_lock:
406+
407+
with self._frame_lock:
408+
with timing.measure("Multi.store_latest"):
408409
self._frames[camera_id] = frame
409410
self._timestamps[camera_id] = timestamp
410411

411-
# Emit frame data without tiling (tiling done in GUI for performance)
412-
if self._frames:
413-
ordered_frames: dict[str, np.ndarray] = {}
414-
ordered_timestamps: dict[str, float] = {}
415-
416-
for cam_id in self._camera_display_order:
417-
if cam_id in self._frames:
418-
ordered_frames[cam_id] = self._frames[cam_id]
419-
if cam_id in self._timestamps:
420-
ordered_timestamps[cam_id] = self._timestamps[cam_id]
421-
422-
# Any unexpected/legacy IDs, appended deterministically.
423-
for cam_id in self._frames:
424-
if cam_id not in ordered_frames:
425-
ordered_frames[cam_id] = self._frames[cam_id]
426-
for cam_id in self._timestamps:
427-
if cam_id not in ordered_timestamps:
428-
ordered_timestamps[cam_id] = self._timestamps[cam_id]
429-
430-
frame_data = MultiFrameData(
431-
frames=ordered_frames,
432-
timestamps=ordered_timestamps,
433-
source_camera_id=camera_id,
434-
tiled_frame=None,
435-
)
412+
with timing.measure("Multi.build_ordered"):
413+
ordered_frames: dict[str, np.ndarray] = {}
414+
ordered_timestamps: dict[str, float] = {}
415+
416+
for cam_id in self._camera_display_order:
417+
if cam_id in self._frames:
418+
ordered_frames[cam_id] = self._frames[cam_id]
419+
if cam_id in self._timestamps:
420+
ordered_timestamps[cam_id] = self._timestamps[cam_id]
421+
422+
# Any unexpected/legacy IDs, appended deterministically.
423+
for cam_id in self._frames:
424+
if cam_id not in ordered_frames:
425+
ordered_frames[cam_id] = self._frames[cam_id]
426+
for cam_id in self._timestamps:
427+
if cam_id not in ordered_timestamps:
428+
ordered_timestamps[cam_id] = self._timestamps[cam_id]
429+
430+
with timing.measure("Multi.construct_frame_data"):
431+
frame_data = MultiFrameData(
432+
frames=ordered_frames,
433+
timestamps=ordered_timestamps,
434+
source_camera_id=camera_id,
435+
tiled_frame=None,
436+
)
437+
438+
if frame_data is not None:
439+
with timing.measure("Multi.emit.frame_ready"):
436440
self.frame_ready.emit(frame_data)
441+
437442
timing.note_frame()
438443
timing.maybe_log()
439444

0 commit comments

Comments
 (0)