-
Notifications
You must be signed in to change notification settings - Fork 10.9k
Fix: Safe camera detection for macOS (M1/M2) to prevent OpenCV AVX/th… #1236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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...") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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): | ||
|
|
||
There was a problem hiding this comment.
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.