forked from Project-Babble/ProjectBabble
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmisc_utils.py
183 lines (145 loc) · 5.06 KB
/
misc_utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import typing
import serial
import sys
import glob
import os
import platform
import cv2
import re
import subprocess
bg_color_highlight = "#424042"
bg_color_clear = "#242224"
# Detect the operating system
is_nt = os.name == "nt"
os_type = platform.system()
if is_nt:
from pygrabber.dshow_graph import FilterGraph
graph = FilterGraph()
def is_valid_float_input(value):
# Allow empty string, negative sign, or a float number
return bool(re.match(r"^-?\d*\.?\d*$", value))
def is_valid_int_input(value):
# Allow empty string, negative sign, or an integer number
return bool(re.match(r"^-?\d*$", value))
def list_camera_names():
cam_list = graph.get_input_devices()
cam_names = []
for index, name in enumerate(cam_list):
cam_names.append(name)
cam_names = cam_names + list_serial_ports()
return cam_names
def list_cameras_opencv():
"""Use OpenCV to check available cameras by index (fallback for Linux/macOS)"""
index = 0
arr = []
while True:
cap = cv2.VideoCapture(index)
if not cap.read()[0]:
break
else:
arr.append(f"/dev/video{index}")
cap.release()
index += 1
return arr
def is_uvc_device(device):
"""Check if the device is a UVC video device (not metadata)"""
try:
result = subprocess.run(
["v4l2-ctl", f"--device={device}", "--all"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
output = result.stdout.decode("utf-8")
# Check if "UVC Payload Header Metadata" is in the output
if "UVC Payload Header Metadata" in output:
return False # It's metadata, not actual video
return True # It's a valid video device
except Exception as e:
return False
def list_linux_uvc_devices():
"""List UVC video devices on Linux (excluding metadata devices)"""
try:
# v4l2-ctl --list-devices breaks if video devices are non-sequential.
# So this might be better?
result = glob.glob("/dev/video*");
devices = []
current_device = None
for line in result:
if is_uvc_device(line):
devices.append(
line
) # We return the path like '/dev/video0'
return devices
except Exception as e:
return [f"Error listing UVC devices on Linux: {str(e)}"]
def list_camera_names():
"""Cross-platform function to list camera names"""
if is_nt:
# On Windows, use pygrabber to list devices
cam_list = graph.get_input_devices()
return cam_list + list_serial_ports()
elif os_type == "Linux":
# On Linux, return UVC device paths like '/dev/video0'
return list_linux_uvc_devices() + list_serial_ports()
elif os_type == "Darwin":
# On macOS, fallback to OpenCV (device names aren't fetched)
return list_cameras_opencv() + list_serial_ports()
else:
return ["Unsupported operating system"]
def list_serial_ports():
#print("DEBUG: Listed Serial Ports")
""" Lists serial port names
:raises EnvironmentError:
On unsupported or unknown platforms
:returns:
A list of the serial ports available on the system
"""
if sys.platform.startswith("win"):
ports = ["COM%s" % (i + 1) for i in range(256)]
elif sys.platform.startswith("linux") or sys.platform.startswith("cygwin"):
# this excludes your current terminal "/dev/tty"
ports = glob.glob("/dev/tty[A-Za-z]*")
elif sys.platform.startswith("darwin"):
ports = glob.glob("/dev/tty.*")
else:
raise EnvironmentError("Unsupported platform")
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, serial.SerialException):
pass
return result
def get_camera_index_by_name(name):
"""Cross-platform function to get the camera index by its name or path"""
cam_list = list_camera_names()
# On Linux, we use device paths like '/dev/video0' and match directly
# OpenCV expects the actual /dev/video#, not the offset into the device list
if os_type == "Linux":
return int(str.replace(name,"/dev/video",""));
# On Windows, match by camera name
elif is_nt:
for i, device_name in enumerate(cam_list):
if device_name == name:
return i
# On macOS or other systems, fallback to OpenCV device index
elif os_type == "Darwin":
for i, device in enumerate(cam_list):
if device == name:
return i
return None
# Placeholder for sound functions on Windows
def PlaySound(*args, **kwargs):
pass
# Handle debugging virtual envs.
def EnsurePath():
if os.path.exists(os.path.join(os.getcwd(), "BabbleApp")):
os.chdir(os.path.join(os.getcwd(), "BabbleApp"))
SND_FILENAME = SND_ASYNC = 1
if is_nt:
import winsound
PlaySound = winsound.PlaySound
SND_FILENAME = winsound.SND_FILENAME
SND_ASYNC = winsound.SND_ASYNC