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/video/capture/linux/video_capture_device_factory_linux.h" | 5 #include "media/video/capture/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 #if defined(OS_OPENBSD) | 9 #if defined(OS_OPENBSD) |
10 #include <sys/videoio.h> | 10 #include <sys/videoio.h> |
11 #else | 11 #else |
12 #include <linux/videodev2.h> | 12 #include <linux/videodev2.h> |
13 #endif | 13 #endif |
14 #include <sys/ioctl.h> | 14 #include <sys/ioctl.h> |
15 | 15 |
16 #include "base/files/file_enumerator.h" | 16 #include "base/files/file_enumerator.h" |
17 #include "base/files/scoped_file.h" | 17 #include "base/files/scoped_file.h" |
18 #include "base/posix/eintr_wrapper.h" | 18 #include "base/posix/eintr_wrapper.h" |
19 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
20 #if defined(OS_CHROMEOS) | 20 #if defined(OS_CHROMEOS) |
21 #include "media/video/capture/linux/video_capture_device_chromeos.h" | 21 #include "media/video/capture/linux/video_capture_device_chromeos.h" |
22 #endif | 22 #endif |
23 #include "media/video/capture/linux/video_capture_device_linux.h" | 23 #include "media/video/capture/linux/video_capture_device_linux.h" |
24 | 24 |
25 namespace media { | 25 namespace media { |
26 | 26 |
27 static bool HasUsableFormats(int fd) { | 27 static int Ioctl(const base::ScopedFD& device_fd, int request, void* arg) { |
28 v4l2_fmtdesc fmtdesc; | 28 return VideoCaptureDeviceLinux::Ioctl(device_fd, request, arg); |
29 std::list<int> usable_fourccs; | 29 } |
30 | 30 |
31 media::VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false, | 31 static bool HasUsableFormats(const base::ScopedFD& device_fd) { |
32 &usable_fourccs); | 32 const std::list<int>& usable_fourccs = |
33 VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false); | |
33 | 34 |
34 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); | 35 v4l2_fmtdesc fmtdesc = {}; |
35 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 36 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
36 | 37 for (; Ioctl(device_fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) { |
37 while (HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0) { | |
38 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), | 38 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), |
39 fmtdesc.pixelformat) != usable_fourccs.end()) | 39 fmtdesc.pixelformat) != usable_fourccs.end()) |
40 return true; | 40 return true; |
41 | |
42 fmtdesc.index++; | |
43 } | 41 } |
44 return false; | 42 return false; |
45 } | 43 } |
46 | 44 |
47 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( | 45 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( |
48 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | 46 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
49 : ui_task_runner_(ui_task_runner) { | 47 : ui_task_runner_(ui_task_runner) { |
50 } | 48 } |
51 | 49 |
52 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { | 50 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { |
(...skipping 20 matching lines...) Expand all Loading... | |
73 return scoped_ptr<VideoCaptureDevice>(); | 71 return scoped_ptr<VideoCaptureDevice>(); |
74 } | 72 } |
75 | 73 |
76 return scoped_ptr<VideoCaptureDevice>(self); | 74 return scoped_ptr<VideoCaptureDevice>(self); |
77 } | 75 } |
78 | 76 |
79 void VideoCaptureDeviceFactoryLinux::GetDeviceNames( | 77 void VideoCaptureDeviceFactoryLinux::GetDeviceNames( |
80 VideoCaptureDevice::Names* const device_names) { | 78 VideoCaptureDevice::Names* const device_names) { |
81 DCHECK(thread_checker_.CalledOnValidThread()); | 79 DCHECK(thread_checker_.CalledOnValidThread()); |
82 DCHECK(device_names->empty()); | 80 DCHECK(device_names->empty()); |
83 base::FilePath path("/dev/"); | 81 const base::FilePath path("/dev/"); |
84 base::FileEnumerator enumerator( | 82 base::FileEnumerator enumerator( |
85 path, false, base::FileEnumerator::FILES, "video*"); | 83 path, false, base::FileEnumerator::FILES, "video*"); |
86 | 84 |
87 while (!enumerator.Next().empty()) { | 85 while (!enumerator.Next().empty()) { |
88 base::FileEnumerator::FileInfo info = enumerator.GetInfo(); | 86 const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); |
89 | 87 const std::string unique_id = path.value() + info.GetName().value(); |
90 std::string unique_id = path.value() + info.GetName().value(); | 88 const base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); |
91 base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); | |
92 if (!fd.is_valid()) { | 89 if (!fd.is_valid()) { |
93 // Failed to open this device. | 90 DLOG(ERROR) << "Couldn't open " << info.GetName().value(); |
94 continue; | 91 continue; |
95 } | 92 } |
96 // Test if this is a V4L2 capture device. | 93 // Test if this is a V4L2 capture device and if it has at least one |
94 // supported capture format. Single plane capture devices should not be | |
95 // output devices, see http://crbug.com/139356. | |
perkj_chrome
2014/12/16 10:34:43
? Can you expand on this?
mcasas
2014/12/16 18:08:17
Done.
| |
97 v4l2_capability cap; | 96 v4l2_capability cap; |
98 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && | 97 if ((Ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) && |
99 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && | 98 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && |
100 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { | 99 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && |
perkj_chrome
2014/12/16 10:34:43
the indentation was corret from the beginning.
mcasas
2014/12/16 18:08:17
Done.
| |
101 // This is a V4L2 video capture device | 100 HasUsableFormats(fd)) { |
102 if (HasUsableFormats(fd.get())) { | 101 device_names->push_front(VideoCaptureDevice::Name( |
103 VideoCaptureDevice::Name device_name(base::StringPrintf("%s", cap.card), | 102 base::StringPrintf("%s", cap.card), unique_id)); |
104 unique_id); | |
105 device_names->push_back(device_name); | |
106 } else { | |
107 DVLOG(1) << "No usable formats reported by " << info.GetName().value(); | |
108 } | |
109 } | 103 } |
110 } | 104 } |
111 } | 105 } |
112 | 106 |
113 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( | 107 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( |
114 const VideoCaptureDevice::Name& device, | 108 const VideoCaptureDevice::Name& device, |
115 VideoCaptureFormats* supported_formats) { | 109 VideoCaptureFormats* supported_formats) { |
116 DCHECK(thread_checker_.CalledOnValidThread()); | 110 DCHECK(thread_checker_.CalledOnValidThread()); |
117 if (device.id().empty()) | 111 if (device.id().empty()) |
118 return; | 112 return; |
119 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); | 113 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); |
120 if (!fd.is_valid()) { | 114 if (!fd.is_valid()) // Failed to open this device. |
121 // Failed to open this device. | |
122 return; | 115 return; |
123 } | |
124 supported_formats->clear(); | 116 supported_formats->clear(); |
125 | 117 |
126 // Retrieve the caps one by one, first get pixel format, then sizes, then | 118 // Retrieve the caps one by one, first get pixel format, then sizes, then |
127 // frame rates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. | 119 // frame rates. |
128 v4l2_fmtdesc pixel_format = {}; | 120 v4l2_fmtdesc pixel_format = {}; |
129 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 121 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
130 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FMT, &pixel_format)) == 0) { | 122 for (; Ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format) == 0; ++pixel_format.index) { |
131 VideoCaptureFormat supported_format; | 123 VideoCaptureFormat supported_format; |
132 supported_format.pixel_format = | 124 supported_format.pixel_format = |
133 VideoCaptureDeviceLinux::V4l2ColorToVideoCaptureColorFormat( | 125 VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( |
134 (int32)pixel_format.pixelformat); | 126 pixel_format.pixelformat); |
135 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) { | 127 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
136 ++pixel_format.index; | |
137 continue; | 128 continue; |
138 } | |
139 | 129 |
140 v4l2_frmsizeenum frame_size = {}; | 130 v4l2_frmsizeenum frame_size = {}; |
141 frame_size.pixel_format = pixel_format.pixelformat; | 131 frame_size.pixel_format = pixel_format.pixelformat; |
142 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMESIZES, &frame_size)) == | 132 for (; Ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0; |
143 0) { | 133 ++frame_size.index) { |
144 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { | 134 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { |
145 supported_format.frame_size.SetSize( | 135 supported_format.frame_size.SetSize( |
146 frame_size.discrete.width, frame_size.discrete.height); | 136 frame_size.discrete.width, frame_size.discrete.height); |
147 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { | 137 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE || |
148 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 138 frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { |
149 NOTIMPLEMENTED(); | |
150 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { | |
151 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 139 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
152 NOTIMPLEMENTED(); | 140 NOTIMPLEMENTED(); |
153 } | 141 } |
142 | |
154 v4l2_frmivalenum frame_interval = {}; | 143 v4l2_frmivalenum frame_interval = {}; |
155 frame_interval.pixel_format = pixel_format.pixelformat; | 144 frame_interval.pixel_format = pixel_format.pixelformat; |
156 frame_interval.width = frame_size.discrete.width; | 145 frame_interval.width = frame_size.discrete.width; |
157 frame_interval.height = frame_size.discrete.height; | 146 frame_interval.height = frame_size.discrete.height; |
158 std::list<float> frame_rates; | 147 std::list<float> frame_rates; |
159 while (HANDLE_EINTR(ioctl( | 148 for (; Ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval) == 0; |
160 fd.get(), VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) == 0) { | 149 ++frame_interval.index) { |
perkj_chrome
2014/12/16 10:34:43
nit indentation.
mcasas
2014/12/16 18:08:17
Done.
| |
161 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { | 150 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { |
162 if (frame_interval.discrete.numerator != 0) { | 151 if (frame_interval.discrete.numerator != 0) { |
163 frame_rates.push_back( | 152 frame_rates.push_back(frame_interval.discrete.denominator / |
164 static_cast<float>(frame_interval.discrete.denominator) / | |
165 static_cast<float>(frame_interval.discrete.numerator)); | 153 static_cast<float>(frame_interval.discrete.numerator)); |
166 } | 154 } |
167 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { | 155 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS || |
168 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 156 frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { |
169 NOTIMPLEMENTED(); | |
170 break; | |
171 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { | |
172 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 157 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
173 NOTIMPLEMENTED(); | 158 NOTIMPLEMENTED(); |
174 break; | 159 break; |
175 } | 160 } |
176 ++frame_interval.index; | |
177 } | 161 } |
162 // Some devices, e.g. Kinect, do not enumerate any frame rates, see | |
163 // http://crbug.com/412284. Set their frame_rate to zero. | |
164 if (frame_rates.empty()) | |
165 frame_rates.push_back(0.0f); | |
178 | 166 |
179 // Some devices, e.g. Kinect, do not enumerate any frame rates. For these | 167 for (const auto& it : frame_rates) { |
180 // devices, we do not want to lose all enumeration (pixel format and | 168 supported_format.frame_rate = it; |
181 // resolution), so we return a frame rate of zero instead. | |
182 if (frame_rates.empty()) | |
183 frame_rates.push_back(0); | |
184 | |
185 for (std::list<float>::iterator it = frame_rates.begin(); | |
186 it != frame_rates.end(); ++it) { | |
187 supported_format.frame_rate = *it; | |
188 supported_formats->push_back(supported_format); | 169 supported_formats->push_back(supported_format); |
189 DVLOG(1) << device.name() << " " << supported_format.ToString(); | 170 DVLOG(1) << device.name() << " " << supported_format.ToString(); |
190 } | 171 } |
191 ++frame_size.index; | |
192 } | 172 } |
193 ++pixel_format.index; | |
194 } | 173 } |
195 return; | 174 return; |
196 } | 175 } |
197 | 176 |
198 // static | 177 // static |
199 VideoCaptureDeviceFactory* | 178 VideoCaptureDeviceFactory* |
200 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( | 179 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( |
201 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 180 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { |
202 return new VideoCaptureDeviceFactoryLinux(ui_task_runner); | 181 return new VideoCaptureDeviceFactoryLinux(ui_task_runner); |
203 } | 182 } |
204 | 183 |
205 } // namespace media | 184 } // namespace media |
OLD | NEW |