Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 21 additions & 55 deletions modules/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -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).
"""
Comment on lines 801 to +805
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Clarify behavior differences across platforms in the docstring.

Also note that on Windows the function enumerates devices via DirectShow; add this to the docstring to distinguish platform strategies.

Suggested change
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).
"""
def get_available_cameras():
"""
Safe camera detection that avoids threading and AVX crashes.
On macOS and Unix-like systems, it utilizes a safe detection mechanism to list available cameras.
On Windows, devices are enumerated via DirectShow.
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...")
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Use a logging framework instead of print statements.

A logging framework provides configurable levels and outputs, improving maintainability and configurability of debug and error messages in production.

Suggested implementation:

import logging
# (other imports below)
            logging.error(f"[Camera Detection Error - Windows]: {e}")
        logging.info("Safely checking for available cameras...")
            logging.warning("Default camera (index 0) not available.")
        logging.error(f"[Camera Detection Error - Unix]: {e}")

Please ensure that the logging configuration (level, formatting, etc.) is set up in your application so that these logging calls behave as expected. If there is an existing logging setup in your code base, this configuration might already be in place.

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):
Expand Down