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 bool HasUsableFormats(int fd) { |
28 v4l2_fmtdesc fmtdesc; | 28 const std::list<int>& usable_fourccs = |
29 std::list<int> usable_fourccs; | 29 VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false); |
30 | 30 |
31 media::VideoCaptureDeviceLinux::GetListOfUsableFourCCs(false, | 31 v4l2_fmtdesc fmtdesc = {}; |
32 &usable_fourccs); | |
33 | |
34 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); | |
35 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 32 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
36 | 33 for (; HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0; |
37 while (HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) == 0) { | 34 ++fmtdesc.index) { |
perkj_chrome
2014/12/16 20:28:28
++ goes underneath ;
mcasas
2014/12/16 23:50:31
Done.
| |
38 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), | 35 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), |
39 fmtdesc.pixelformat) != usable_fourccs.end()) | 36 fmtdesc.pixelformat) != usable_fourccs.end()) |
40 return true; | 37 return true; |
41 | |
42 fmtdesc.index++; | |
43 } | 38 } |
44 return false; | 39 return false; |
45 } | 40 } |
46 | 41 |
47 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( | 42 VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux( |
48 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | 43 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
49 : ui_task_runner_(ui_task_runner) { | 44 : ui_task_runner_(ui_task_runner) { |
50 } | 45 } |
51 | 46 |
52 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { | 47 VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() { |
(...skipping 20 matching lines...) Expand all Loading... | |
73 return scoped_ptr<VideoCaptureDevice>(); | 68 return scoped_ptr<VideoCaptureDevice>(); |
74 } | 69 } |
75 | 70 |
76 return scoped_ptr<VideoCaptureDevice>(self); | 71 return scoped_ptr<VideoCaptureDevice>(self); |
77 } | 72 } |
78 | 73 |
79 void VideoCaptureDeviceFactoryLinux::GetDeviceNames( | 74 void VideoCaptureDeviceFactoryLinux::GetDeviceNames( |
80 VideoCaptureDevice::Names* const device_names) { | 75 VideoCaptureDevice::Names* const device_names) { |
81 DCHECK(thread_checker_.CalledOnValidThread()); | 76 DCHECK(thread_checker_.CalledOnValidThread()); |
82 DCHECK(device_names->empty()); | 77 DCHECK(device_names->empty()); |
83 base::FilePath path("/dev/"); | 78 const base::FilePath path("/dev/"); |
84 base::FileEnumerator enumerator( | 79 base::FileEnumerator enumerator( |
85 path, false, base::FileEnumerator::FILES, "video*"); | 80 path, false, base::FileEnumerator::FILES, "video*"); |
86 | 81 |
87 while (!enumerator.Next().empty()) { | 82 while (!enumerator.Next().empty()) { |
88 base::FileEnumerator::FileInfo info = enumerator.GetInfo(); | 83 const base::FileEnumerator::FileInfo info = enumerator.GetInfo(); |
89 | 84 const std::string unique_id = path.value() + info.GetName().value(); |
90 std::string unique_id = path.value() + info.GetName().value(); | 85 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()) { | 86 if (!fd.is_valid()) { |
93 // Failed to open this device. | 87 DLOG(ERROR) << "Couldn't open " << info.GetName().value(); |
94 continue; | 88 continue; |
95 } | 89 } |
96 // Test if this is a V4L2 capture device. | 90 // Test if this is a V4L2 capture device and if it has at least one |
91 // supported capture format. Devices that have capture and output | |
92 // capabilities at the same time are memory-to-memory and are skipped, see | |
93 // http://crbug.com/139356. | |
97 v4l2_capability cap; | 94 v4l2_capability cap; |
98 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && | 95 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && |
99 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && | 96 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE && |
100 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { | 97 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) && |
101 // This is a V4L2 video capture device | 98 HasUsableFormats(fd.get())) { |
102 if (HasUsableFormats(fd.get())) { | 99 device_names->push_front(VideoCaptureDevice::Name( |
103 VideoCaptureDevice::Name device_name(base::StringPrintf("%s", cap.card), | 100 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 } | 101 } |
110 } | 102 } |
111 } | 103 } |
112 | 104 |
113 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( | 105 void VideoCaptureDeviceFactoryLinux::GetDeviceSupportedFormats( |
114 const VideoCaptureDevice::Name& device, | 106 const VideoCaptureDevice::Name& device, |
115 VideoCaptureFormats* supported_formats) { | 107 VideoCaptureFormats* supported_formats) { |
116 DCHECK(thread_checker_.CalledOnValidThread()); | 108 DCHECK(thread_checker_.CalledOnValidThread()); |
117 if (device.id().empty()) | 109 if (device.id().empty()) |
118 return; | 110 return; |
119 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); | 111 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); |
120 if (!fd.is_valid()) { | 112 if (!fd.is_valid()) // Failed to open this device. |
121 // Failed to open this device. | |
122 return; | 113 return; |
123 } | |
124 supported_formats->clear(); | 114 supported_formats->clear(); |
125 | 115 |
126 // Retrieve the caps one by one, first get pixel format, then sizes, then | 116 // 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. | 117 // frame rates. |
128 v4l2_fmtdesc pixel_format = {}; | 118 v4l2_fmtdesc pixel_format = {}; |
129 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 119 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
130 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FMT, &pixel_format)) == 0) { | 120 for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FMT, &pixel_format)) == 0; |
121 ++pixel_format.index) { | |
131 VideoCaptureFormat supported_format; | 122 VideoCaptureFormat supported_format; |
132 supported_format.pixel_format = | 123 supported_format.pixel_format = |
133 VideoCaptureDeviceLinux::V4l2ColorToVideoCaptureColorFormat( | 124 VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( |
134 (int32)pixel_format.pixelformat); | 125 pixel_format.pixelformat); |
135 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) { | 126 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
136 ++pixel_format.index; | |
137 continue; | 127 continue; |
138 } | |
139 | 128 |
140 v4l2_frmsizeenum frame_size = {}; | 129 v4l2_frmsizeenum frame_size = {}; |
141 frame_size.pixel_format = pixel_format.pixelformat; | 130 frame_size.pixel_format = pixel_format.pixelformat; |
142 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMESIZES, &frame_size)) == | 131 for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMESIZES, &frame_size)) |
143 0) { | 132 == 0; ++frame_size.index) { |
perkj_chrome
2014/12/16 20:28:28
Can you indent this the same way as you do on line
mcasas
2014/12/16 23:50:30
Done.
| |
144 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { | 133 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { |
145 supported_format.frame_size.SetSize( | 134 supported_format.frame_size.SetSize( |
146 frame_size.discrete.width, frame_size.discrete.height); | 135 frame_size.discrete.width, frame_size.discrete.height); |
147 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { | 136 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE || |
148 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 137 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. | 138 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
152 NOTIMPLEMENTED(); | 139 NOTIMPLEMENTED(); |
153 } | 140 } |
141 | |
154 v4l2_frmivalenum frame_interval = {}; | 142 v4l2_frmivalenum frame_interval = {}; |
155 frame_interval.pixel_format = pixel_format.pixelformat; | 143 frame_interval.pixel_format = pixel_format.pixelformat; |
156 frame_interval.width = frame_size.discrete.width; | 144 frame_interval.width = frame_size.discrete.width; |
157 frame_interval.height = frame_size.discrete.height; | 145 frame_interval.height = frame_size.discrete.height; |
158 std::list<float> frame_rates; | 146 std::list<float> frame_rates; |
159 while (HANDLE_EINTR(ioctl( | 147 for (; HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMEINTERVALS, |
160 fd.get(), VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) == 0) { | 148 &frame_interval)) == 0; |
149 ++frame_interval.index) { | |
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) { |
perkj_chrome
2014/12/16 20:28:28
indentation
mcasas
2014/12/16 23:50:30
Done.
| |
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 |