Last active
December 29, 2022 04:03
-
-
Save thevickypedia/1b0c75483905a79951757ecf8e69a44b to your computer and use it in GitHub Desktop.
Get information and list cameras for Linux, macOS and Windows
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import platform | |
import subprocess | |
from typing import Dict, Iterable, List, Union | |
Windows = """wmic path CIM_LogicalDevice where "Description like 'USB Video%'" get /value""" | |
Darwin = "system_profiler SPCameraDataType" | |
Linux = "v4l2-ctl --list-devices" | |
def list_splitter(original_list: List[str], delimiter: str) -> List[List[str]]: | |
"""Splits a list into multiple lists at a specific value given. | |
Notes: | |
delimiter: This value should be final value where the initial list must be split. | |
See Also: | |
.. code-block:: python | |
main_list = ['First Name', 'Vignesh', 'Last Name', 'Rao', 'Drives', 'Jaguar', | |
'First Name', 'Tony', 'Last Name', 'Stark', 'Drives', 'Mark III'] | |
- delimiter should be ``Drives`` since that's where the main list has to be split. | |
Args: | |
original_list: List that has to be split. | |
delimiter: Value where the list has to be split. | |
Returns: | |
List[List[str]]: | |
Returns list of list(s). | |
""" | |
# Split indices at the required value where the list as to be split and rebuilt as a new one | |
split_indices = [index + 1 for index, val in enumerate(original_list) if val.startswith(delimiter)] | |
# Rebuild the new list split at the given index value | |
return [original_list[i: j] for i, j in | |
zip([0] + split_indices, | |
split_indices + ([len(original_list)] if split_indices[-1] != len(original_list) else []))] | |
class Camera: | |
"""Initiates camera object to get information about the connected cameras. | |
>>> Camera | |
""" | |
def __init__(self): | |
"""Instantiates the camera object to run the OS specific builtin commands to get the camera information. | |
Raises: | |
CameraError: | |
If unable to connect to the camera. | |
""" | |
if platform.system() == "Darwin": | |
cmd = Darwin | |
elif platform.system() == "Windows": | |
cmd = Windows | |
elif platform.system() == "Linux": | |
cmd = Linux | |
else: | |
cmd = "" | |
self.output, err = subprocess.Popen( | |
cmd, | |
shell=True, | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE, | |
).communicate() | |
if error := err.decode(encoding='UTF-8'): | |
raise SystemError(error) | |
self.output = self.output.decode(encoding='UTF-8').splitlines() | |
def _get_camera_info_linux(self) -> Iterable[str]: | |
"""Get camera information for Linux. | |
Warnings: | |
- Results will be yielded in raw terminal output format. | |
Yields: | |
List[str]: | |
Returns the information of all connected cameras as a list of string. | |
""" | |
for cam in self.output: | |
if cam.strip().startswith('/dev/video'): | |
result = subprocess.check_output(f"v4l2-ctl --device={cam.strip()} --all", shell=True) | |
yield result.decode(encoding='UTF-8') | |
def _list_cameras_linux(self) -> Iterable[str]: | |
"""Yields the camera name for Linux. | |
Yields: | |
Names of the connected cameras. | |
""" | |
for cam in self.output: | |
if cam.strip().startswith('/dev/video'): | |
try: | |
result = subprocess.check_output(f"v4l2-ctl --device={cam.strip()} --all | grep Name", shell=True) | |
yield result.decode(encoding='UTF-8').replace('Name', '').strip().lstrip(':').strip() | |
except subprocess.CalledProcessError: | |
continue | |
def _get_camera_info_windows(self) -> Iterable[Dict[str, str]]: | |
"""Get camera information for WindowsOS. | |
Yields: | |
List[Dict[str, str]]: | |
Returns the information of all connected cameras as a list of dictionary. | |
""" | |
output = list(filter(None, self.output)) # Filter null values in the list | |
if not output: | |
return | |
for list_ in list_splitter(original_list=output, delimiter='SystemName'): | |
values = {} | |
for sub_list in list_: | |
values[sub_list.split('=')[0]] = sub_list.split('=')[1] | |
yield values | |
def _list_cameras_windows(self) -> Iterable[str]: | |
"""Yields the camera name for WindowsOS. | |
Yields: | |
Names of the connected cameras. | |
""" | |
for camera in self._get_camera_info_windows(): | |
yield camera.get('Name') | |
def _get_camera_info_darwin(self) -> Iterable[Dict[str, str]]: | |
"""Get camera information for macOS. | |
Returns: | |
Dict[str, Dict]: | |
Returns the raw XML output as a dictionary. | |
""" | |
output = list(filter(None, self.output)) | |
if not output: | |
return | |
output = [v.strip() for v in output][1:] | |
for list_ in list_splitter(original_list=output, delimiter='Unique ID'): | |
values = {} | |
for sub_list in list_: | |
if sub_list.endswith(':'): | |
values['Name'] = sub_list.rstrip(':') | |
else: | |
values[sub_list.split(':')[0]] = sub_list.split(':')[1] | |
yield values | |
def _list_cameras_darwin(self) -> Iterable[str]: | |
"""Yields the camera name for macOS. | |
Yields: | |
List[str]: | |
Names of the connected cameras. | |
""" | |
for camera in self._get_camera_info_darwin(): | |
yield camera.get('Name') | |
def get_camera_info(self) -> List[Union[Dict[str, str], str]]: | |
"""Gets the yielded camera information as a generator object and returns as a list. | |
Returns: | |
List[Dict[str]]: | |
List of dictionaries. | |
""" | |
if platform.system() == "Darwin": | |
return list(self._get_camera_info_darwin()) | |
elif platform.system() == "Windows": | |
return list(self._get_camera_info_windows()) | |
elif platform.system() == "Linux": | |
return list(self._get_camera_info_linux()) | |
def list_cameras(self) -> List[str]: | |
"""List of names of all cameras connected. | |
Returns: | |
List[str]: | |
List of camera names. | |
""" | |
if platform.system() == "Darwin": | |
return list(self._list_cameras_darwin()) | |
elif platform.system() == "Windows": | |
return list(self._list_cameras_windows()) | |
elif platform.system() == "Linux": | |
return list(self._list_cameras_linux()) | |
def get_index(self) -> str: | |
"""Get the index and name of each connected camera. | |
Returns: | |
str: | |
Index and name of cameras as a string. | |
""" | |
return '\n'.join([f"{i}: {c}" for i, c in enumerate(self.list_cameras())]) | |
if __name__ == '__main__': | |
print(Camera().get_index()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment