OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/capture/video/linux/video_capture_device_factory_linux.h" | 5 #include "media/capture/video/linux/video_capture_device_factory_linux.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 #include <sys/ioctl.h> | 10 #include <sys/ioctl.h> |
11 | 11 |
12 #include "base/files/file_enumerator.h" | 12 #include "base/files/file_enumerator.h" |
13 #include "base/files/scoped_file.h" | 13 #include "base/files/scoped_file.h" |
14 #include "base/posix/eintr_wrapper.h" | 14 #include "base/posix/eintr_wrapper.h" |
| 15 #include "base/strings/stringprintf.h" |
15 #include "build/build_config.h" | 16 #include "build/build_config.h" |
16 | 17 |
17 #if defined(OS_OPENBSD) | 18 #if defined(OS_OPENBSD) |
18 #include <sys/videoio.h> | 19 #include <sys/videoio.h> |
19 #else | 20 #else |
20 #include <linux/videodev2.h> | 21 #include <linux/videodev2.h> |
21 #endif | 22 #endif |
22 | 23 |
23 #if defined(OS_CHROMEOS) | 24 #if defined(OS_CHROMEOS) |
24 #include "media/capture/video/linux/video_capture_device_chromeos.h" | 25 #include "media/capture/video/linux/video_capture_device_chromeos.h" |
25 #endif | 26 #endif |
26 #include "media/capture/video/linux/video_capture_device_linux.h" | 27 #include "media/capture/video/linux/video_capture_device_linux.h" |
27 | 28 |
28 namespace media { | 29 namespace media { |
29 | 30 |
| 31 // USB VID and PID are both 4 bytes long. |
| 32 static const size_t kVidPidSize = 4; |
| 33 |
| 34 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding |
| 35 // USB device info directory. |
| 36 static const char kVidPathTemplate[] = |
| 37 "/sys/class/video4linux/%s/device/../idVendor"; |
| 38 static const char kPidPathTemplate[] = |
| 39 "/sys/class/video4linux/%s/device/../idProduct"; |
| 40 |
| 41 static bool ReadIdFile(const std::string& path, std::string* id) { |
| 42 char id_buf[kVidPidSize]; |
| 43 FILE* file = fopen(path.c_str(), "rb"); |
| 44 if (!file) |
| 45 return false; |
| 46 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1; |
| 47 fclose(file); |
| 48 if (!success) |
| 49 return false; |
| 50 id->append(id_buf, kVidPidSize); |
| 51 return true; |
| 52 } |
| 53 |
30 static bool HasUsableFormats(int fd, uint32_t capabilities) { | 54 static bool HasUsableFormats(int fd, uint32_t capabilities) { |
31 if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE)) | 55 if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE)) |
32 return false; | 56 return false; |
33 | 57 |
34 const std::list<uint32_t>& usable_fourccs = | 58 const std::list<uint32_t>& usable_fourccs = |
35 VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false); | 59 VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false); |
36 v4l2_fmtdesc fmtdesc = {}; | 60 v4l2_fmtdesc fmtdesc = {}; |
37 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 61 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
38 for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0; | 62 for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0; |
39 ++fmtdesc.index) { | 63 ++fmtdesc.index) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 } | 145 } |
122 | 146 |
123 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( | 147 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( |
124 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | 148 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
125 : ui_task_runner_(ui_task_runner) { | 149 : ui_task_runner_(ui_task_runner) { |
126 } | 150 } |
127 | 151 |
128 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { | 152 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { |
129 } | 153 } |
130 | 154 |
131 std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryLinux::Create( | 155 std::unique_ptr<VideoCaptureDevice> |
132 const VideoCaptureDevice::Name& device_name) { | 156 VideoCaptureDeviceFactoryLinux::CreateDevice( |
| 157 const VideoCaptureDeviceDescriptor& device_descriptor) { |
133 DCHECK(thread_checker_.CalledOnValidThread()); | 158 DCHECK(thread_checker_.CalledOnValidThread()); |
134 #if defined(OS_CHROMEOS) | 159 #if defined(OS_CHROMEOS) |
135 VideoCaptureDeviceChromeOS* self = | 160 VideoCaptureDeviceChromeOS* self = |
136 new VideoCaptureDeviceChromeOS(ui_task_runner_, device_name); | 161 new VideoCaptureDeviceChromeOS(ui_task_runner_, device_descriptor); |
137 #else | 162 #else |
138 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); | 163 VideoCaptureDeviceLinux* self = |
| 164 new VideoCaptureDeviceLinux(device_descriptor); |
139 #endif | 165 #endif |
140 if (!self) | 166 if (!self) |
141 return std::unique_ptr<VideoCaptureDevice>(); | 167 return std::unique_ptr<VideoCaptureDevice>(); |
142 // Test opening the device driver. This is to make sure it is available. | 168 // Test opening the device driver. This is to make sure it is available. |
143 // We will reopen it again in our worker thread when someone | 169 // We will reopen it again in our worker thread when someone |
144 // allocates the camera. | 170 // allocates the camera. |
145 base::ScopedFD fd(HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY))); | 171 base::ScopedFD fd( |
| 172 HANDLE_EINTR(open(device_descriptor.device_id.c_str(), O_RDONLY))); |
146 if (!fd.is_valid()) { | 173 if (!fd.is_valid()) { |
147 DLOG(ERROR) << "Cannot open device"; | 174 DLOG(ERROR) << "Cannot open device"; |
148 delete self; | 175 delete self; |
149 return std::unique_ptr<VideoCaptureDevice>(); | 176 return std::unique_ptr<VideoCaptureDevice>(); |
150 } | 177 } |
151 | 178 |
152 return std::unique_ptr<VideoCaptureDevice>(self); | 179 return std::unique_ptr<VideoCaptureDevice>(self); |
153 } | 180 } |
154 | 181 |
155 void VideoCaptureDeviceFactoryLinux::GetDeviceNames( | 182 void VideoCaptureDeviceFactoryLinux::GetDeviceDescriptors( |
156 VideoCaptureDevice::Names* const device_names) { | 183 VideoCaptureDeviceDescriptors* device_descriptors) { |
157 DCHECK(thread_checker_.CalledOnValidThread()); | 184 DCHECK(thread_checker_.CalledOnValidThread()); |
158 DCHECK(device_names->empty()); | 185 DCHECK(device_descriptors->empty()); |
159 const base::FilePath path("/dev/"); | 186 const base::FilePath path("/dev/"); |
160 base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES, | 187 base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES, |
161 "video*"); | 188 "video*"); |
162 | 189 |
163 while (!enumerator.Next().empty()) { | 190 while (!enumerator.Next().empty()) { |
164 const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); | 191 const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); |
165 const std::string unique_id = path.value() + info.GetName().value(); | 192 const std::string unique_id = path.value() + info.GetName().value(); |
166 const base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); | 193 const base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); |
167 if (!fd.is_valid()) { | 194 if (!fd.is_valid()) { |
168 DLOG(ERROR) << "Couldn't open " << info.GetName().value(); | 195 DLOG(ERROR) << "Couldn't open " << info.GetName().value(); |
169 continue; | 196 continue; |
170 } | 197 } |
171 // Test if this is a V4L2 capture device and if it has at least one | 198 // Test if this is a V4L2 capture device and if it has at least one |
172 // supported capture format. Devices that have capture and output | 199 // supported capture format. Devices that have capture and output |
173 // capabilities at the same time are memory-to-memory and are skipped, see | 200 // capabilities at the same time are memory-to-memory and are skipped, see |
174 // http://crbug.com/139356. | 201 // http://crbug.com/139356. |
175 v4l2_capability cap; | 202 v4l2_capability cap; |
176 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && | 203 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && |
177 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && | 204 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && |
178 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && | 205 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && |
179 HasUsableFormats(fd.get(), cap.capabilities)) { | 206 HasUsableFormats(fd.get(), cap.capabilities)) { |
180 device_names->push_back(VideoCaptureDevice::Name( | 207 const std::string model_id = GetDeviceModelId(unique_id); |
181 reinterpret_cast<char*>(cap.card), unique_id, | 208 device_descriptors->emplace_back( |
182 VideoCaptureDevice::Name::V4L2_SINGLE_PLANE)); | 209 reinterpret_cast<char*>(cap.card), unique_id, model_id, |
| 210 VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE); |
183 } | 211 } |
184 } | 212 } |
185 } | 213 } |
186 | 214 |
187 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( | 215 void VideoCaptureDeviceFactoryLinux::GetSupportedFormats( |
188 const VideoCaptureDevice::Name& device, | 216 const VideoCaptureDeviceDescriptor& device, |
189 VideoCaptureFormats* supported_formats) { | 217 VideoCaptureFormats* supported_formats) { |
190 DCHECK(thread_checker_.CalledOnValidThread()); | 218 DCHECK(thread_checker_.CalledOnValidThread()); |
191 if (device.id().empty()) | 219 if (device.device_id.empty()) |
192 return; | 220 return; |
193 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); | 221 base::ScopedFD fd(HANDLE_EINTR(open(device.device_id.c_str(), O_RDONLY))); |
194 if (!fd.is_valid()) // Failed to open this device. | 222 if (!fd.is_valid()) // Failed to open this device. |
195 return; | 223 return; |
196 supported_formats->clear(); | 224 supported_formats->clear(); |
197 | 225 |
198 DCHECK_NE(device.capture_api_type(), | 226 DCHECK_NE(device.capture_api, VideoCaptureApi::UNKNOWN); |
199 VideoCaptureDevice::Name::API_TYPE_UNKNOWN); | |
200 GetSupportedFormatsForV4L2BufferType(fd.get(), supported_formats); | 227 GetSupportedFormatsForV4L2BufferType(fd.get(), supported_formats); |
201 } | 228 } |
202 | 229 |
| 230 std::string VideoCaptureDeviceFactoryLinux::GetDeviceModelId( |
| 231 const std::string& device_id) { |
| 232 // |unique_id| is of the form "/dev/video2". |file_name| is "video2". |
| 233 const std::string dev_dir = "/dev/"; |
| 234 DCHECK_EQ(0, device_id.compare(0, dev_dir.length(), dev_dir)); |
| 235 const std::string file_name = |
| 236 device_id.substr(dev_dir.length(), device_id.length()); |
| 237 |
| 238 const std::string vidPath = |
| 239 base::StringPrintf(kVidPathTemplate, file_name.c_str()); |
| 240 const std::string pidPath = |
| 241 base::StringPrintf(kPidPathTemplate, file_name.c_str()); |
| 242 |
| 243 std::string usb_id; |
| 244 if (!ReadIdFile(vidPath, &usb_id)) |
| 245 return ""; |
| 246 usb_id.append(":"); |
| 247 if (!ReadIdFile(pidPath, &usb_id)) |
| 248 return ""; |
| 249 |
| 250 return usb_id; |
| 251 } |
| 252 |
203 // static | 253 // static |
204 VideoCaptureDeviceFactory* | 254 VideoCaptureDeviceFactory* |
205 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( | 255 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( |
206 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 256 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { |
207 return new VideoCaptureDeviceFactoryLinux(ui_task_runner); | 257 return new VideoCaptureDeviceFactoryLinux(ui_task_runner); |
208 } | 258 } |
209 | 259 |
210 } // namespace media | 260 } // namespace media |
OLD | NEW |