Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: media/capture/video/linux/video_capture_device_factory_linux.cc

Issue 2214533002: move //media/capture to //device/capture (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "media/capture/video/linux/video_capture_device_factory_linux.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stdint.h>
10 #include <sys/ioctl.h>
11
12 #include "base/files/file_enumerator.h"
13 #include "base/files/scoped_file.h"
14 #include "base/posix/eintr_wrapper.h"
15 #include "base/strings/stringprintf.h"
16 #include "build/build_config.h"
17
18 #if defined(OS_OPENBSD)
19 #include <sys/videoio.h>
20 #else
21 #include <linux/videodev2.h>
22 #endif
23
24 #if defined(OS_CHROMEOS)
25 #include "media/capture/video/linux/video_capture_device_chromeos.h"
26 #endif
27 #include "media/capture/video/linux/video_capture_device_linux.h"
28
29 namespace media {
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
54 static bool HasUsableFormats(int fd, uint32_t capabilities) {
55 if (!(capabilities & V4L2_CAP_VIDEO_CAPTURE))
56 return false;
57
58 const std::list<uint32_t>& usable_fourccs =
59 VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false);
60 v4l2_fmtdesc fmtdesc = {};
61 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
62 for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0;
63 ++fmtdesc.index) {
64 if (std::find(usable_fourccs.begin(), usable_fourccs.end(),
65 fmtdesc.pixelformat) != usable_fourccs.end()) {
66 return true;
67 }
68 }
69
70 DLOG(ERROR) << "No usable formats found";
71 return false;
72 }
73
74 static std::list<float> GetFrameRateList(int fd,
75 uint32_t fourcc,
76 uint32_t width,
77 uint32_t height) {
78 std::list<float> frame_rates;
79
80 v4l2_frmivalenum frame_interval = {};
81 frame_interval.pixel_format = fourcc;
82 frame_interval.width = width;
83 frame_interval.height = height;
84 for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) ==
85 0;
86 ++frame_interval.index) {
87 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
88 if (frame_interval.discrete.numerator != 0) {
89 frame_rates.push_back(
90 frame_interval.discrete.denominator /
91 static_cast<float>(frame_interval.discrete.numerator));
92 }
93 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS ||
94 frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
95 // TODO(mcasas): see http://crbug.com/249953, support these devices.
96 NOTIMPLEMENTED();
97 break;
98 }
99 }
100 // Some devices, e.g. Kinect, do not enumerate any frame rates, see
101 // http://crbug.com/412284. Set their frame_rate to zero.
102 if (frame_rates.empty())
103 frame_rates.push_back(0);
104 return frame_rates;
105 }
106
107 static void GetSupportedFormatsForV4L2BufferType(
108 int fd,
109 media::VideoCaptureFormats* supported_formats) {
110 v4l2_fmtdesc v4l2_format = {};
111 v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
112 for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &v4l2_format)) == 0;
113 ++v4l2_format.index) {
114 VideoCaptureFormat supported_format;
115 supported_format.pixel_format =
116 VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat(
117 v4l2_format.pixelformat);
118
119 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN)
120 continue;
121
122 v4l2_frmsizeenum frame_size = {};
123 frame_size.pixel_format = v4l2_format.pixelformat;
124 for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size)) == 0;
125 ++frame_size.index) {
126 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
127 supported_format.frame_size.SetSize(frame_size.discrete.width,
128 frame_size.discrete.height);
129 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE ||
130 frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
131 // TODO(mcasas): see http://crbug.com/249953, support these devices.
132 NOTIMPLEMENTED();
133 }
134
135 const std::list<float> frame_rates = GetFrameRateList(
136 fd, v4l2_format.pixelformat, frame_size.discrete.width,
137 frame_size.discrete.height);
138 for (const auto& frame_rate : frame_rates) {
139 supported_format.frame_rate = frame_rate;
140 supported_formats->push_back(supported_format);
141 DVLOG(1) << VideoCaptureFormat::ToString(supported_format);
142 }
143 }
144 }
145 }
146
147 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux(
148 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
149 : ui_task_runner_(ui_task_runner) {
150 }
151
152 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() {
153 }
154
155 std::unique_ptr<VideoCaptureDevice>
156 VideoCaptureDeviceFactoryLinux::CreateDevice(
157 const VideoCaptureDeviceDescriptor& device_descriptor) {
158 DCHECK(thread_checker_.CalledOnValidThread());
159 #if defined(OS_CHROMEOS)
160 VideoCaptureDeviceChromeOS* self =
161 new VideoCaptureDeviceChromeOS(ui_task_runner_, device_descriptor);
162 #else
163 VideoCaptureDeviceLinux* self =
164 new VideoCaptureDeviceLinux(device_descriptor);
165 #endif
166 if (!self)
167 return std::unique_ptr<VideoCaptureDevice>();
168 // Test opening the device driver. This is to make sure it is available.
169 // We will reopen it again in our worker thread when someone
170 // allocates the camera.
171 base::ScopedFD fd(
172 HANDLE_EINTR(open(device_descriptor.device_id.c_str(), O_RDONLY)));
173 if (!fd.is_valid()) {
174 DLOG(ERROR) << "Cannot open device";
175 delete self;
176 return std::unique_ptr<VideoCaptureDevice>();
177 }
178
179 return std::unique_ptr<VideoCaptureDevice>(self);
180 }
181
182 void VideoCaptureDeviceFactoryLinux::GetDeviceDescriptors(
183 VideoCaptureDeviceDescriptors* device_descriptors) {
184 DCHECK(thread_checker_.CalledOnValidThread());
185 DCHECK(device_descriptors->empty());
186 const base::FilePath path("/dev/");
187 base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES,
188 "video*");
189
190 while (!enumerator.Next().empty()) {
191 const base::FileEnumerator::FileInfo info = enumerator.GetInfo();
192 const std::string unique_id = path.value() + info.GetName().value();
193 const base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY)));
194 if (!fd.is_valid()) {
195 DLOG(ERROR) << "Couldn't open " << info.GetName().value();
196 continue;
197 }
198 // Test if this is a V4L2 capture device and if it has at least one
199 // supported capture format. Devices that have capture and output
200 // capabilities at the same time are memory-to-memory and are skipped, see
201 // http://crbug.com/139356.
202 v4l2_capability cap;
203 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
204 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE &&
205 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) &&
206 HasUsableFormats(fd.get(), cap.capabilities)) {
207 const std::string model_id = GetDeviceModelId(unique_id);
208 device_descriptors->emplace_back(
209 reinterpret_cast<char*>(cap.card), unique_id, model_id,
210 VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE);
211 }
212 }
213 }
214
215 void VideoCaptureDeviceFactoryLinux::GetSupportedFormats(
216 const VideoCaptureDeviceDescriptor& device,
217 VideoCaptureFormats* supported_formats) {
218 DCHECK(thread_checker_.CalledOnValidThread());
219 if (device.device_id.empty())
220 return;
221 base::ScopedFD fd(HANDLE_EINTR(open(device.device_id.c_str(), O_RDONLY)));
222 if (!fd.is_valid()) // Failed to open this device.
223 return;
224 supported_formats->clear();
225
226 DCHECK_NE(device.capture_api, VideoCaptureApi::UNKNOWN);
227 GetSupportedFormatsForV4L2BufferType(fd.get(), supported_formats);
228 }
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
253 // static
254 VideoCaptureDeviceFactory*
255 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory(
256 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
257 return new VideoCaptureDeviceFactoryLinux(ui_task_runner);
258 }
259
260 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/video/linux/video_capture_device_factory_linux.h ('k') | media/capture/video/linux/video_capture_device_linux.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698