From c1a6dc693d2296c52ed47572836c5178d1516de7 Mon Sep 17 00:00:00 2001
From: Bryn Whyman <15868440+brynwhyman@users.noreply.github.com>
Date: Thu, 8 May 2025 20:40:22 +1200
Subject: [PATCH] Fix: Safe camera detection for macOS (M1/M2) to prevent
 OpenCV AVX/thread crashes

---
 modules/ui.py | 76 ++++++++++++++-------------------------------------
 1 file changed, 21 insertions(+), 55 deletions(-)

diff --git a/modules/ui.py b/modules/ui.py
index 94fa5cf..32a0669 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -799,73 +799,39 @@ def webcam_preview(root: ctk.CTk, camera_index: int):
 
 
 def get_available_cameras():
-    """Returns a list of available camera names and indices."""
+    """
+    Safe camera detection for macOS and Unix-like systems that avoids threading and AVX crashes.
+    Returns a tuple of (camera_indices, camera_names).
+    """
+    import cv2
+    import platform
+
     if platform.system() == "Windows":
         try:
+            from pygrabber.dshow_graph import FilterGraph
             graph = FilterGraph()
             devices = graph.get_input_devices()
-
-            # Create list of indices and names
             camera_indices = list(range(len(devices)))
             camera_names = devices
-
-            # If no cameras found through DirectShow, try OpenCV fallback
-            if not camera_names:
-                # Try to open camera with index -1 and 0
-                test_indices = [-1, 0]
-                working_cameras = []
-
-                for idx in test_indices:
-                    cap = cv2.VideoCapture(idx)
-                    if cap.isOpened():
-                        working_cameras.append(f"Camera {idx}")
-                        cap.release()
-
-                if working_cameras:
-                    return test_indices[: len(working_cameras)], working_cameras
-
-            # If still no cameras found, return empty lists
             if not camera_names:
                 return [], ["No cameras found"]
-
             return camera_indices, camera_names
-
         except Exception as e:
-            print(f"Error detecting cameras: {str(e)}")
-            return [], ["No cameras found"]
-    else:
-        # Unix-like systems (Linux/Mac) camera detection
-        camera_indices = []
-        camera_names = []
-
-        if platform.system() == "Darwin":  # macOS specific handling
-            # Try to open the default FaceTime camera first
-            cap = cv2.VideoCapture(0)
-            if cap.isOpened():
-                camera_indices.append(0)
-                camera_names.append("FaceTime Camera")
-                cap.release()
-
-            # On macOS, additional cameras typically use indices 1 and 2
-            for i in [1, 2]:
-                cap = cv2.VideoCapture(i)
-                if cap.isOpened():
-                    camera_indices.append(i)
-                    camera_names.append(f"Camera {i}")
-                    cap.release()
-        else:
-            # Linux camera detection - test first 10 indices
-            for i in range(10):
-                cap = cv2.VideoCapture(i)
-                if cap.isOpened():
-                    camera_indices.append(i)
-                    camera_names.append(f"Camera {i}")
-                    cap.release()
-
-        if not camera_names:
+            print(f"[Camera Detection Error - Windows]: {e}")
             return [], ["No cameras found"]
 
-        return camera_indices, camera_names
+    # macOS or Linux
+    try:
+        print("[Info] Safely checking for available cameras...")
+        cap = cv2.VideoCapture(0)
+        if cap is None or not cap.isOpened():
+            print("[Warning] Default camera (index 0) not available.")
+            return [], ["No cameras found"]
+        cap.release()
+        return [0], ["Default Camera (Index 0)"]
+    except Exception as e:
+        print(f"[Camera Detection Error - Unix]: {e}")
+        return [], ["No cameras found"]
 
 
 def create_webcam_preview(camera_index: int):