Skip to content

Instantly share code, notes, and snippets.

@thevickypedia
Last active December 29, 2022 04:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thevickypedia/1b0c75483905a79951757ecf8e69a44b to your computer and use it in GitHub Desktop.
Save thevickypedia/1b0c75483905a79951757ecf8e69a44b to your computer and use it in GitHub Desktop.
Get information and list cameras for Linux, macOS and Windows
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