Index: media/capture/video/linux/video_capture_device_factory_linux.cc |
diff --git a/media/capture/video/linux/video_capture_device_factory_linux.cc b/media/capture/video/linux/video_capture_device_factory_linux.cc |
index 4cba194dfb24b2caa7caca13c5bd8f677abfcb86..abe433706718f047473a27d28e46c72a93d7887b 100644 |
--- a/media/capture/video/linux/video_capture_device_factory_linux.cc |
+++ b/media/capture/video/linux/video_capture_device_factory_linux.cc |
@@ -12,6 +12,7 @@ |
#include "base/files/file_enumerator.h" |
#include "base/files/scoped_file.h" |
#include "base/posix/eintr_wrapper.h" |
+#include "base/strings/stringprintf.h" |
#include "build/build_config.h" |
#if defined(OS_OPENBSD) |
@@ -27,6 +28,29 @@ |
namespace media { |
+// USB VID and PID are both 4 bytes long. |
+static const size_t kVidPidSize = 4; |
+ |
+// /sys/class/video4linux/video{N}/device is a symlink to the corresponding |
+// USB device info directory. |
+static const char kVidPathTemplate[] = |
+ "/sys/class/video4linux/%s/device/../idVendor"; |
+static const char kPidPathTemplate[] = |
+ "/sys/class/video4linux/%s/device/../idProduct"; |
+ |
+static bool ReadIdFile(const std::string& path, std::string* id) { |
+ char id_buf[kVidPidSize]; |
+ FILE* file = fopen(path.c_str(), "rb"); |
+ if (!file) |
+ return false; |
+ const bool success = fread(id_buf, kVidPidSize, 1, file) == 1; |
+ fclose(file); |
+ if (!success) |
+ return false; |
+ id->append(id_buf, kVidPidSize); |
+ return true; |
+} |
+ |
static bool HasUsableFormats(int fd, uint32_t capabilities) { |
if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE)) |
return false; |
@@ -128,21 +152,24 @@ VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( |
VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { |
} |
-std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryLinux::Create( |
- const VideoCaptureDevice::Name& device_name) { |
+std::unique_ptr<VideoCaptureDevice> |
+VideoCaptureDeviceFactoryLinux::CreateDevice( |
+ const VideoCaptureDeviceDescriptor& device_descriptor) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
#if defined(OS_CHROMEOS) |
VideoCaptureDeviceChromeOS* self = |
- new VideoCaptureDeviceChromeOS(ui_task_runner_, device_name); |
+ new VideoCaptureDeviceChromeOS(ui_task_runner_, device_descriptor); |
#else |
- VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); |
+ VideoCaptureDeviceLinux* self = |
+ new VideoCaptureDeviceLinux(device_descriptor); |
#endif |
if (!self) |
return std::unique_ptr<VideoCaptureDevice>(); |
// Test opening the device driver. This is to make sure it is available. |
// We will reopen it again in our worker thread when someone |
// allocates the camera. |
- base::ScopedFD fd(HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY))); |
+ base::ScopedFD fd( |
+ HANDLE_EINTR(open(device_descriptor.device_id.c_str(), O_RDONLY))); |
if (!fd.is_valid()) { |
DLOG(ERROR) << "Cannot open device"; |
delete self; |
@@ -152,10 +179,10 @@ std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryLinux::Create( |
return std::unique_ptr<VideoCaptureDevice>(self); |
} |
-void VideoCaptureDeviceFactoryLinux::GetDeviceNames( |
- VideoCaptureDevice::Names* const device_names) { |
+void VideoCaptureDeviceFactoryLinux::GetDeviceDescriptors( |
+ VideoCaptureDeviceDescriptors* device_descriptors) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- DCHECK(device_names->empty()); |
+ DCHECK(device_descriptors->empty()); |
const base::FilePath path("/dev/"); |
base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES, |
"video*"); |
@@ -177,29 +204,52 @@ void VideoCaptureDeviceFactoryLinux::GetDeviceNames( |
(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && |
!(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && |
HasUsableFormats(fd.get(), cap.capabilities)) { |
- device_names->push_back(VideoCaptureDevice::Name( |
- reinterpret_cast<char*>(cap.card), unique_id, |
- VideoCaptureDevice::Name::V4L2_SINGLE_PLANE)); |
+ const std::string model_id = GetDeviceModelId(unique_id); |
+ device_descriptors->emplace_back( |
+ reinterpret_cast<char*>(cap.card), unique_id, model_id, |
+ VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE); |
} |
} |
} |
-void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( |
- const VideoCaptureDevice::Name& device, |
+void VideoCaptureDeviceFactoryLinux::GetSupportedFormats( |
+ const VideoCaptureDeviceDescriptor& device, |
VideoCaptureFormats* supported_formats) { |
DCHECK(thread_checker_.CalledOnValidThread()); |
- if (device.id().empty()) |
+ if (device.device_id.empty()) |
return; |
- base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); |
+ base::ScopedFD fd(HANDLE_EINTR(open(device.device_id.c_str(), O_RDONLY))); |
if (!fd.is_valid()) // Failed to open this device. |
return; |
supported_formats->clear(); |
- DCHECK_NE(device.capture_api_type(), |
- VideoCaptureDevice::Name::API_TYPE_UNKNOWN); |
+ DCHECK_NE(device.capture_api, VideoCaptureApi::UNKNOWN); |
GetSupportedFormatsForV4L2BufferType(fd.get(), supported_formats); |
} |
+std::string VideoCaptureDeviceFactoryLinux::GetDeviceModelId( |
+ const std::string& device_id) { |
+ // |unique_id| is of the form "/dev/video2". |file_name| is "video2". |
+ const std::string dev_dir = "/dev/"; |
+ DCHECK_EQ(0, device_id.compare(0, dev_dir.length(), dev_dir)); |
+ const std::string file_name = |
+ device_id.substr(dev_dir.length(), device_id.length()); |
+ |
+ const std::string vidPath = |
+ base::StringPrintf(kVidPathTemplate, file_name.c_str()); |
+ const std::string pidPath = |
+ base::StringPrintf(kPidPathTemplate, file_name.c_str()); |
+ |
+ std::string usb_id; |
+ if (!ReadIdFile(vidPath, &usb_id)) |
+ return ""; |
+ usb_id.append(":"); |
+ if (!ReadIdFile(pidPath, &usb_id)) |
+ return ""; |
+ |
+ return usb_id; |
+} |
+ |
// static |
VideoCaptureDeviceFactory* |
VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( |