I have the following code that prints out the names of USB cameras connected to my PC:
import wmi
c = wmi.WMI()
wql = "Select * From Win32_USBControllerDevice"
for item in c.query(wql):
a = item.Dependent.PNPClass
b = item.Dependent.Name.upper()
if (a.upper() == 'MEDIA' or a.upper() == 'CAMERA') and 'AUDIO' not in b:
print(item.Dependent.Name)
The problem with this code is that it only works in Windows. I want to alter this code so that it works on all operating systems. I know that I have to use something other than wmi, since wmi only works in Windows. So, I was thinking about using an ffmpeg wrapper called ffmpy. So maybe I could convert the code to use ffmpy? I got the code above from the following SO post: Associate USB Video Capture Device Friendly Name with OpenCV Port Number in Python. Any help would be much appreciated! Thanks!
You can give pygrabber a shot. "# This code lists the cameras connected to your PC:" (source)
from pygrabber.dshow_graph import FilterGraph
graph = FilterGraph()
print(graph.get_input_devices())
# ['Integrated Webcam', 'EpocCam Camera']
The answer to this question is no; there is no OS-independent way of getting the names of USB cameras connected to your PC. However, there is platform-specific code that can get the job done: https://stackoverflow.com/a/68402011/13386603
Related
I'm trying to create a program where I have to read a pcap file and then count the number of packets related to some IPs. I'm not used to program in Python but I have to use it because I'm using it on a Raspberry Pi and depending of the output I have to control several pins.
Right now I have this, but I have an error and I don´t know how to solve it.
from scapy.all import *
from scapy.utils import RawPcapReader
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, TCP
def read_pcap(name_pcap):
print("Opening", name_pcap)
client_1 = '192.168.4.4:48878'
server = '10.0.0.2:80'
(client_1_ip, client_1_port) = client_1.split(':')
(server_ip, server_port) = server.split(':')
counter = 0
for(pkt_data, pkt_metadata,) in RawPcapReader(name_pcap):
counter += 1
ether_pkt = Ether(pkt_data)
# Below here are functions to filter the data
read_pcap("captura.pcap")
And the error is this one:
NameError: name 'Packet' is not defined
The error apears to be in this (for(pkt_data, pkt_metadata,) in RawPcapReader(name_pcap):) line.
Someone knows how to solve it?
Thnak you :)
As Carcigenicate pointed out, that's a known bug. It's fixed in https://github.com/secdev/scapy/commit/ff644181d9bee35979a84671690d8cd1aa1971fa
You can use the development version (over https://scapy.readthedocs.io/en/latest/installation.html#current-development-version) in the meantime
Uninstall previous version & Install Latest version from https://pypi.org/project/scapy/
pip install scapy==2.5.0rc1
This should fix the error
I'm having some trouble enumerating over cameras in Python over multiple OS's.
Here's some of the approaches I've tried:
import cv2 as cv
num = 0
while 1:
cap = cv.VideoCapture(num)
if cap.isOpened():
# working capture
num += 1
else:
break
The downsides of using Opencv is that Opencv doesn't provide any friendly display name. Additionally, enumerating over cameras is slow, as you need to actually open and close the camera to check if it's a valid camera.
I've also tried using libraries like PyPylon and pyuvc. They work, but only for specific brands.
I've done some researching on stack overflow, and some people have suggested python's gstreamer bindings as a possible OS independent solution. This is what I have so far.
import pgi
pgi.require_version("Gtk", "3.0")
pgi.require_version("Gst", "1.0")
pgi.require_version("GstVideo", "1.0")
from pgi.repository import Gtk, GObject, Gst, GstVideo
Gst.init("")
dm = Gst.DeviceMonitor()
dm.set_show_all_devices(True)
dm.start()
print("Displaying devices.")
for device in dm.get_devices():
print(device.get_display_name())
print("Displaying providers.")
for provider in dm.get_providers():
print(provider)
dm.stop()
This is the output I'm getting:
Displaying devices.
papalook Microphone
DisplayPort
HDMI
Built-in Output
Built-in Microph
Displaying providers.
osxaudiodeviceprovider
For some reason, I'm not getting any webcams, but only audio devices.
Any ideas on what I'm doing wrong?
Any different approaches I should be taking?
Thanks.
I recently encountered this problem and didn't even realize how hard it is!
Sharing here my solution, hopefully it helps someone.
As already pointed out, there is no easy way of doing this in a cross platform manner and we still need to write platform specific code.
My solution is actually combination of some of the approaches offered here, so let's break it down.
1. Get the index of a camera
First thing we want to tackle is how many camera devices is connected to the computer.
We can use OpenCV for this and the approach that was already mentioned above.
2. Linux
Linux stores information about video devices at /sys/class/video4linux
Since we know the index of each camera, we can do something like this to get extra info.
cat /sys/class/video4linux/video1/name
3. Windows
Windows provides a bunch of useful APIs through the Windows Runtime also known as WinRT.
Microsoft provides a Python library for this and to get the camera information we need to use DevicesEnumeration API.
4. MacOS
For MacOs, we can use a similar approach as for Linux. It seems that the ioreg and system_profiler commands can provide camera name information.
Unfortunately, I don't have a MacOS system to test this out so I left a TODO. It would be great if someone can try and share it.
Here is my code.
import asyncio
import platform
import subprocess
import cv2
if platform.system() == 'Windows':
import winrt.windows.devices.enumeration as windows_devices
VIDEO_DEVICES = 4
class Camera:
def __init__(self):
self.cameras = []
def get_camera_info(self) -> list:
self.cameras = []
camera_indexes = self.get_camera_indexes()
if len(camera_indexes) == 0:
return self.cameras
self.cameras = self.add_camera_information(camera_indexes)
return self.cameras
def get_camera_indexes(self):
index = 0
camera_indexes = []
max_numbers_of_cameras_to_check = 10
while max_numbers_of_cameras_to_check > 0:
capture = cv2.VideoCapture(index)
if capture.read()[0]:
camera_indexes.append(index)
capture.release()
index += 1
max_numbers_of_cameras_to_check -= 1
return camera_indexes
# TODO add MacOS specific implementations
def add_camera_information(self, camera_indexes: list) -> list:
platform_name = platform.system()
cameras = []
if platform_name == 'Windows':
cameras_info_windows = asyncio.run(self.get_camera_information_for_windows())
for camera_index in camera_indexes:
camera_name = cameras_info_windows.get_at(camera_index).name.replace('\n', '')
cameras.append({'camera_index': camera_index, 'camera_name': camera_name})
return cameras
if platform_name == 'Linux':
for camera_index in camera_indexes:
camera_name = subprocess.run(['cat', '/sys/class/video4linux/video{}/name'.format(camera_index)],
stdout=subprocess.PIPE).stdout.decode('utf-8')
camera_name = camera_name.replace('\n', '')
cameras.append({'camera_index': camera_index, 'camera_name': camera_name})
return cameras
async def get_camera_information_for_windows(self):
return await windows_devices.DeviceInformation.find_all_async(VIDEO_DEVICES)
camera = Camera()
For Windows you can use the library pygrabber which is a pure python tool to capture photos from cameras and for doing simple image processing using DirectShow and OpenCV. It also enumerates the connected webcams like so:
from __future__ import print_function
from pygrabber.dshow_graph import FilterGraph
graph = FilterGraph()
print(graph.get_input_devices())
I have modified the library to work under Python 2 and 3. Download at:
https://github.com/bunkahle/pygrabber
Original source only for Python 3:
https://github.com/andreaschiavinato/python_grabber
I have installed the FTDI libftd2xx.so following the FTDI installation guide. I also has the libMPSSE.so downloaded. I am writing a python wrapper to use the I2C functions in the libMPSSE.so
However, I got the following error when trying to run my code:
../../TopLayer/I2C/src/ftdi_i2c.c:239:I2C_InitChannel(): NULL expression encountered
According to https://stackoverflow.com/a/22994703/8406938, looks like it cannot find the libftd2xx.so
Here is my python wrapper:
filepath = 'my path to the libMPSSE.so'
mpsse = CDLL(os.path.join(filepath, 'libMPSSE.so')
ChannelConf = ChannelConfig()
ChannelConf.clock_rate = 100000
ChannelConf.LatencyTimer = 3
ChannelConf.Options = 0
status = mpsse.I2C_InitChannel(c_void_p()), byref(ChannelConf))
The exact same code work in my Windows machine with libMPSSE.dll with the windows driver. Any suggestion how to solve this?
I had interfaced R305 biometric module with microcontrollers before using embedded C. But when I tried it using python, I am having error in sending hex array to it. Here is my code:
import serial
adrport = serial.Serial(port="/dev/tty0",baudrate=9600)
genimg = [0xEF,0x01,0xFF,0xFF,0xFF,0xFF,0x01,0x00,0x03,0x01,0x00,0x05]
also I tried it declaring like this:
genimg = "\xEF\x01\xFF\xFF\xFF\xFF\x01\x00\x03\x01\x00\x05"
I used to transfer the above mentioned array using the following function:
txd(genimg)
def txd(tx):
adrport.write(bytearray(tx))
Also I tried using
adrport.write(bytes(tx))
It doesnot show any errors to post the traceback, but the biometric module is not responding.
Okay, I changed the serail port to "/ttyAMA0" & now I can see the data flowing.But it also includes both "[,]" along with commas","; Can anybody help.?
Finally got the answer,defined array as
genimg = "\xEF\x01\xFF\xFF\xFF\xFF\x01\x00\x03\x01\x00\x05"
and used this.
adrport.write(bytes(tx))
Note: I tried this combination earlier also, but got loop iteration error because of using same name for both array and function. My bad,sorry everyone -;)
I am using python to populate a table with the file pathways of a number of stored files. However the pathway needs to have the full network drive computer name not just the drive letter, ie
//ComputerName/folder/subfolder/file
not
P:/folder/subfolder/file
I have investigated using the win32api, win32file, and os.path modules but nothing is looking like its able to do it. I need something like win32api.GetComputerName() but with the ability to drop in a known drive letter as an argument and it return the computer name that is mapped to the letter.
So is there anyway in python to look up a drive letter and get back the computer name?
Network drives are mapped using the Windows Networking API that's exported by mpr.dll (multiple provider router). You can create a network drive via WNetAddConnection2. To get the remote path that's associated with a local device, call WNetGetConnection. You can do this using ctypes as follows:
import ctypes
from ctypes import wintypes
mpr = ctypes.WinDLL('mpr')
ERROR_SUCCESS = 0x0000
ERROR_MORE_DATA = 0x00EA
wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
mpr.WNetGetConnectionW.restype = wintypes.DWORD
mpr.WNetGetConnectionW.argtypes = (wintypes.LPCWSTR,
wintypes.LPWSTR,
wintypes.LPDWORD)
def get_connection(local_name):
length = (wintypes.DWORD * 1)()
result = mpr.WNetGetConnectionW(local_name, None, length)
if result != ERROR_MORE_DATA:
raise ctypes.WinError(result)
remote_name = (wintypes.WCHAR * length[0])()
result = mpr.WNetGetConnectionW(local_name, remote_name, length)
if result != ERROR_SUCCESS:
raise ctypes.WinError(result)
return remote_name.value
For example:
>>> subprocess.call(r'net use Y: \\live.sysinternals.com\tools')
The command completed successfully.
0
>>> print(get_connection('Y:'))
\\live.sysinternals.com\tools
I think you just need to look at more of pywin32... As you can see here, there is already an API that converts local drive names to full UNC paths.
For completeness, here is some code that works for me.
import win32wnet
import sys
print(win32wnet.WNetGetUniversalName(sys.argv[1], 1))
And this gives me something like this when I run it:
C:\test>python get_unc.py i:\some\path
\\machine\test_share\some\path
you could run net use and parse the output.
i am posting this from my mobile but i am going to improve this answer when i am in front of a real computer.
here are some links, that can help in the meantime:
https://docs.python.org/2/library/subprocess.html#module-subprocess.
https://technet.microsoft.com/en-us/library/gg651155.aspx.
My answer to a similar question:
Here's how to do it in python ≥ 3.4, with no dependencies!*
from pathlib import Path
def unc_drive(file_path):
return str(Path(file_path).resolve())
*Note: I just found a situation in which this method fails. One of my company's network shares has permissions setup such that this method raises a PermissionError. In this case, win32wnet.WNetGetUniversalName is a suitable fallback.
If you just need the hostname, you can use the socket module:
socket.gethostname()
or you may want to use the os module:
os.uname()[1]
os.uname() returns a 5 tuple that contains (sysname, nodename, release, version, machine)