From b64ecd9960d5bba5272608d896055a3345ff87f3 Mon Sep 17 00:00:00 2001 From: Dan Minor Date: Wed, 3 Jun 2020 13:13:30 -0400 Subject: [PATCH] Check V4L2_CAP_VIDEO_CAPTURE when enumerating capture devices on Linux The side effect of not filtering on V4L2_CAP_VIDEO_CAPTURE is that every device is enumerated twice. Because we look up devices by name, and the device that supports V4L2_CAP_VIDEO_CAPTURE seems to always appear first in /dev/video, this does not seem to end up with us ever choosing an inappropriate device. We might get away with just filtering device names from the list, but if the order of devices ever changed in /dev/video there could be problems. Bug: webrtc:11641 Change-Id: I16fee4edc873838ed4643ee16a8bbc699d6bbcf5 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/176460 Reviewed-by: Per Kjellander Commit-Queue: Dan Minor Cr-Commit-Position: refs/heads/master@{#31508} --- .../video_capture/linux/device_info_linux.cc | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/video_capture/linux/device_info_linux.cc b/modules/video_capture/linux/device_info_linux.cc index bac5d4078a..3c8fdd20fa 100644 --- a/modules/video_capture/linux/device_info_linux.cc +++ b/modules/video_capture/linux/device_info_linux.cc @@ -47,11 +47,19 @@ uint32_t DeviceInfoLinux::NumberOfDevices() { uint32_t count = 0; char device[20]; int fd = -1; + struct v4l2_capability cap; /* detect /dev/video [0-63]VideoCaptureModule entries */ for (int n = 0; n < 64; n++) { sprintf(device, "/dev/video%d", n); if ((fd = open(device, O_RDONLY)) != -1) { + // query device capabilities and make sure this is a video capture device + if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || + !(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) { + close(fd); + continue; + } + close(fd); count++; } @@ -74,9 +82,16 @@ int32_t DeviceInfoLinux::GetDeviceName(uint32_t deviceNumber, char device[20]; int fd = -1; bool found = false; + struct v4l2_capability cap; for (int n = 0; n < 64; n++) { sprintf(device, "/dev/video%d", n); if ((fd = open(device, O_RDONLY)) != -1) { + // query device capabilities and make sure this is a video capture device + if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || + !(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) { + close(fd); + continue; + } if (count == deviceNumber) { // Found the device found = true; @@ -92,7 +107,6 @@ int32_t DeviceInfoLinux::GetDeviceName(uint32_t deviceNumber, return -1; // query device capabilities - struct v4l2_capability cap; if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { RTC_LOG(LS_INFO) << "error in querying the device capability for device " << device << ". errno = " << errno; @@ -153,6 +167,11 @@ int32_t DeviceInfoLinux::CreateCapabilityMap(const char* deviceUniqueIdUTF8) { // query device capabilities struct v4l2_capability cap; if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) { + // skip devices without video capture capability + if (!(cap.device_caps & V4L2_CAP_VIDEO_CAPTURE)) { + continue; + } + if (cap.bus_info[0] != 0) { if (strncmp((const char*)cap.bus_info, (const char*)deviceUniqueIdUTF8, strlen((const char*)deviceUniqueIdUTF8)) ==