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 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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> VideoCaptureDeviceFactoryLinux::Create( |
132 const VideoCaptureDevice::Name& device_name) { | 156 const VideoCaptureDeviceDescriptor& device_descriptor) { |
133 DCHECK(thread_checker_.CalledOnValidThread()); | 157 DCHECK(thread_checker_.CalledOnValidThread()); |
134 #if defined(OS_CHROMEOS) | 158 #if defined(OS_CHROMEOS) |
135 VideoCaptureDeviceChromeOS* self = | 159 VideoCaptureDeviceChromeOS* self = |
136 new VideoCaptureDeviceChromeOS(ui_task_runner_, device_name); | 160 new VideoCaptureDeviceChromeOS(ui_task_runner_, device_descriptor); |
137 #else | 161 #else |
138 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); | 162 VideoCaptureDeviceLinux* self = |
| 163 new VideoCaptureDeviceLinux(device_descriptor); |
139 #endif | 164 #endif |
140 if (!self) | 165 if (!self) |
141 return std::unique_ptr<VideoCaptureDevice>(); | 166 return std::unique_ptr<VideoCaptureDevice>(); |
142 // Test opening the device driver. This is to make sure it is available. | 167 // 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 | 168 // We will reopen it again in our worker thread when someone |
144 // allocates the camera. | 169 // allocates the camera. |
145 base::ScopedFD fd(HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY))); | 170 base::ScopedFD fd( |
| 171 HANDLE_EINTR(open(device_descriptor.device_id.c_str(), O_RDONLY))); |
146 if (!fd.is_valid()) { | 172 if (!fd.is_valid()) { |
147 DLOG(ERROR) << "Cannot open device"; | 173 DLOG(ERROR) << "Cannot open device"; |
148 delete self; | 174 delete self; |
149 return std::unique_ptr<VideoCaptureDevice>(); | 175 return std::unique_ptr<VideoCaptureDevice>(); |
150 } | 176 } |
151 | 177 |
152 return std::unique_ptr<VideoCaptureDevice>(self); | 178 return std::unique_ptr<VideoCaptureDevice>(self); |
153 } | 179 } |
154 | 180 |
155 void VideoCaptureDeviceFactoryLinux::GetDeviceNames( | 181 void VideoCaptureDeviceFactoryLinux::GetDeviceDescriptors( |
156 VideoCaptureDevice::Names* const device_names) { | 182 VideoCaptureDeviceDescriptors* device_descriptors) { |
157 DCHECK(thread_checker_.CalledOnValidThread()); | 183 DCHECK(thread_checker_.CalledOnValidThread()); |
158 DCHECK(device_names->empty()); | 184 DCHECK(device_descriptors->empty()); |
159 const base::FilePath path("/dev/"); | 185 const base::FilePath path("/dev/"); |
160 base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES, | 186 base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES, |
161 "video*"); | 187 "video*"); |
162 | 188 |
163 while (!enumerator.Next().empty()) { | 189 while (!enumerator.Next().empty()) { |
164 const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); | 190 const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); |
165 const std::string unique_id = path.value() + info.GetName().value(); | 191 const std::string unique_id = path.value() + info.GetName().value(); |
166 const base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); | 192 const base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); |
167 if (!fd.is_valid()) { | 193 if (!fd.is_valid()) { |
168 DLOG(ERROR) << "Couldn't open " << info.GetName().value(); | 194 DLOG(ERROR) << "Couldn't open " << info.GetName().value(); |
169 continue; | 195 continue; |
170 } | 196 } |
171 // Test if this is a V4L2 capture device and if it has at least one | 197 // 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 | 198 // supported capture format. Devices that have capture and output |
173 // capabilities at the same time are memory-to-memory and are skipped, see | 199 // capabilities at the same time are memory-to-memory and are skipped, see |
174 // http://crbug.com/139356. | 200 // http://crbug.com/139356. |
175 v4l2_capability cap; | 201 v4l2_capability cap; |
176 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && | 202 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && |
177 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && | 203 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && |
178 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && | 204 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && |
179 HasUsableFormats(fd.get(), cap.capabilities)) { | 205 HasUsableFormats(fd.get(), cap.capabilities)) { |
180 device_names->push_back(VideoCaptureDevice::Name( | 206 VideoCaptureDeviceDescriptor descriptor; |
181 reinterpret_cast<char*>(cap.card), unique_id, | 207 descriptor.friendly_name = reinterpret_cast<char*>(cap.card); |
182 VideoCaptureDevice::Name::V4L2_SINGLE_PLANE)); | 208 descriptor.device_id = unique_id; |
| 209 descriptor.capture_api = VideoCaptureApiType::LINUX_V4L2_SINGLE_PLANE; |
| 210 device_descriptors->push_back(descriptor); |
183 } | 211 } |
184 } | 212 } |
185 } | 213 } |
186 | 214 |
| 215 void VideoCaptureDeviceFactoryLinux::GetDeviceInfo( |
| 216 const VideoCaptureDeviceDescriptor& device_descriptor, |
| 217 VideoCaptureDeviceInfo* device_info) { |
| 218 DCHECK(device_info); |
| 219 device_info->descriptor = device_descriptor; |
| 220 GetDeviceSupportedFormats(device_descriptor, |
| 221 &(device_info->supported_formats)); |
| 222 device_info->model_id = GetDeviceModelId(device_descriptor); |
| 223 } |
| 224 |
187 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( | 225 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( |
188 const VideoCaptureDevice::Name& device, | 226 const VideoCaptureDeviceDescriptor& device, |
189 VideoCaptureFormats* supported_formats) { | 227 VideoCaptureFormats* supported_formats) { |
190 DCHECK(thread_checker_.CalledOnValidThread()); | 228 DCHECK(thread_checker_.CalledOnValidThread()); |
191 if (device.id().empty()) | 229 if (device.device_id.empty()) |
192 return; | 230 return; |
193 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); | 231 base::ScopedFD fd(HANDLE_EINTR(open(device.device_id.c_str(), O_RDONLY))); |
194 if (!fd.is_valid()) // Failed to open this device. | 232 if (!fd.is_valid()) // Failed to open this device. |
195 return; | 233 return; |
196 supported_formats->clear(); | 234 supported_formats->clear(); |
197 | 235 |
198 DCHECK_NE(device.capture_api_type(), | 236 DCHECK_NE(device.capture_api, VideoCaptureApiType::API_TYPE_UNKNOWN); |
199 VideoCaptureDevice::Name::API_TYPE_UNKNOWN); | |
200 GetSupportedFormatsForV4L2BufferType(fd.get(), supported_formats); | 237 GetSupportedFormatsForV4L2BufferType(fd.get(), supported_formats); |
201 } | 238 } |
202 | 239 |
| 240 std::string VideoCaptureDeviceFactoryLinux::GetDeviceModelId( |
| 241 const VideoCaptureDeviceDescriptor& device) { |
| 242 // |unique_id| is of the form "/dev/video2". |file_name| is "video2". |
| 243 const std::string dev_dir = "/dev/"; |
| 244 DCHECK_EQ(0, device.device_id.compare(0, dev_dir.length(), dev_dir)); |
| 245 const std::string file_name = |
| 246 device.device_id.substr(dev_dir.length(), device.device_id.length()); |
| 247 |
| 248 const std::string vidPath = |
| 249 base::StringPrintf(kVidPathTemplate, file_name.c_str()); |
| 250 const std::string pidPath = |
| 251 base::StringPrintf(kPidPathTemplate, file_name.c_str()); |
| 252 |
| 253 std::string usb_id; |
| 254 if (!ReadIdFile(vidPath, &usb_id)) |
| 255 return ""; |
| 256 usb_id.append(":"); |
| 257 if (!ReadIdFile(pidPath, &usb_id)) |
| 258 return ""; |
| 259 |
| 260 return usb_id; |
| 261 } |
| 262 |
203 // static | 263 // static |
204 VideoCaptureDeviceFactory* | 264 VideoCaptureDeviceFactory* |
205 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( | 265 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( |
206 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 266 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { |
207 return new VideoCaptureDeviceFactoryLinux(ui_task_runner); | 267 return new VideoCaptureDeviceFactoryLinux(ui_task_runner); |
208 } | 268 } |
209 | 269 |
210 } // namespace media | 270 } // namespace media |
OLD | NEW |