summaryrefslogtreecommitdiff
path: root/plugins/motion_capture/tracker.py
diff options
context:
space:
mode:
authorChristian Kolset <christian.kolset@gmail.com>2026-05-07 14:46:20 -0600
committerChristian Kolset <christian.kolset@gmail.com>2026-06-03 09:50:17 -0600
commit0a8d42501c1bf168bd852537bb3cd18490fac7ee (patch)
treee6e604cb7fc026fed8ffa65ea14929dfabdfbab9 /plugins/motion_capture/tracker.py
parent8e5d0aec942fb9c49040fc525f0d697fd24d7c2f (diff)
Motion capture: camera selection dropdown
Replace camera index spinbox with a combo listing detected cameras by name. On Linux enumerates /dev/video* and reads device names from sysfs (fast, no probing). Fallback probes cv2.VideoCapture indices 0-7 on other platforms. Simulation entry always appended as last option. Also adds explicit simulation mode (index -1) to tracker.start() and a rescan button (⟳) in both the main window and the Settings > Plugins widget. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'plugins/motion_capture/tracker.py')
-rw-r--r--plugins/motion_capture/tracker.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/plugins/motion_capture/tracker.py b/plugins/motion_capture/tracker.py
index 847a170..d65aca1 100644
--- a/plugins/motion_capture/tracker.py
+++ b/plugins/motion_capture/tracker.py
@@ -99,6 +99,13 @@ class CameraTracker:
self.stop()
self._running = True
+ if camera_index == -1:
+ with self._lock:
+ self._simulated = True
+ self._thread = threading.Thread(target=self._run_sim, daemon=True)
+ self._thread.start()
+ return True
+
try:
import cv2
cap = cv2.VideoCapture(camera_index)
@@ -287,6 +294,50 @@ class CameraTracker:
time.sleep(1 / 30)
+# ── Camera enumeration ────────────────────────────────────────────────────────
+
+def list_cameras():
+ """
+ Return list of (index, label) for all detected camera devices.
+
+ On Linux: reads /dev/video* and pulls human-readable names from sysfs.
+ Falls back to probing cv2.VideoCapture indices 0-7 on other platforms.
+ Always appends a Simulation entry.
+ """
+ cameras = []
+
+ import os, glob
+
+ video_nodes = sorted(glob.glob("/dev/video*"))
+ if video_nodes:
+ for path in video_nodes:
+ try:
+ idx = int(path.replace("/dev/video", ""))
+ except ValueError:
+ continue
+ name_path = f"/sys/class/video4linux/video{idx}/name"
+ try:
+ with open(name_path) as f:
+ name = f.read().strip()
+ except OSError:
+ name = path
+ cameras.append((idx, f"{name} [/dev/video{idx}]"))
+ else:
+ # Non-Linux fallback: probe indices
+ try:
+ import cv2
+ for idx in range(8):
+ cap = cv2.VideoCapture(idx)
+ if cap.isOpened():
+ cameras.append((idx, f"Camera {idx}"))
+ cap.release()
+ except ImportError:
+ pass
+
+ cameras.append((-1, "Simulation (no camera)"))
+ return cameras
+
+
# ── Helper ────────────────────────────────────────────────────────────────────
def _make_cv_tracker():