OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_linux.h" | 5 #include "media/video/capture/linux/video_capture_device_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 #include <sys/mman.h> | 15 #include <sys/mman.h> |
16 | 16 |
17 #include <list> | 17 #include <list> |
18 #include <string> | 18 #include <string> |
19 | 19 |
20 #include "base/bind.h" | 20 #include "base/bind.h" |
21 #include "base/files/file_enumerator.h" | 21 #include "base/files/file_enumerator.h" |
22 #include "base/files/scoped_file.h" | |
23 #include "base/posix/eintr_wrapper.h" | 22 #include "base/posix/eintr_wrapper.h" |
24 #include "base/strings/stringprintf.h" | 23 #include "base/strings/stringprintf.h" |
25 | 24 |
26 namespace media { | 25 namespace media { |
27 | 26 |
28 // Max number of video buffers VideoCaptureDeviceLinux can allocate. | 27 // Max number of video buffers VideoCaptureDeviceLinux can allocate. |
29 enum { kMaxVideoBuffers = 2 }; | 28 enum { kMaxVideoBuffers = 2 }; |
30 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw. | 29 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw. |
31 enum { kCaptureTimeoutUs = 200000 }; | 30 enum { kCaptureTimeoutUs = 200000 }; |
32 // The number of continuous timeouts tolerated before treated as error. | 31 // The number of continuous timeouts tolerated before treated as error. |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { | 112 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { |
114 DCHECK(device_names->empty()); | 113 DCHECK(device_names->empty()); |
115 base::FilePath path("/dev/"); | 114 base::FilePath path("/dev/"); |
116 base::FileEnumerator enumerator( | 115 base::FileEnumerator enumerator( |
117 path, false, base::FileEnumerator::FILES, "video*"); | 116 path, false, base::FileEnumerator::FILES, "video*"); |
118 | 117 |
119 while (!enumerator.Next().empty()) { | 118 while (!enumerator.Next().empty()) { |
120 base::FileEnumerator::FileInfo info = enumerator.GetInfo(); | 119 base::FileEnumerator::FileInfo info = enumerator.GetInfo(); |
121 | 120 |
122 std::string unique_id = path.value() + info.GetName().value(); | 121 std::string unique_id = path.value() + info.GetName().value(); |
123 base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY))); | 122 int fd; |
124 if (!fd.is_valid()) { | 123 if ((fd = HANDLE_EINTR(open(unique_id.c_str() , O_RDONLY))) < 0) { |
125 // Failed to open this device. | 124 // Failed to open this device. |
126 continue; | 125 continue; |
127 } | 126 } |
| 127 file_util::ScopedFD fd_closer(&fd); |
128 // Test if this is a V4L2 capture device. | 128 // Test if this is a V4L2 capture device. |
129 v4l2_capability cap; | 129 v4l2_capability cap; |
130 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) && | 130 if ((HANDLE_EINTR(ioctl(fd, VIDIOC_QUERYCAP, &cap)) == 0) && |
131 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && | 131 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && |
132 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { | 132 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { |
133 // This is a V4L2 video capture device | 133 // This is a V4L2 video capture device |
134 if (HasUsableFormats(fd.get())) { | 134 if (HasUsableFormats(fd)) { |
135 Name device_name(base::StringPrintf("%s", cap.card), unique_id); | 135 Name device_name(base::StringPrintf("%s", cap.card), unique_id); |
136 device_names->push_back(device_name); | 136 device_names->push_back(device_name); |
137 } else { | 137 } else { |
138 DVLOG(1) << "No usable formats reported by " << info.GetName().value(); | 138 DVLOG(1) << "No usable formats reported by " << info.GetName().value(); |
139 } | 139 } |
140 } | 140 } |
141 } | 141 } |
142 } | 142 } |
143 | 143 |
144 void VideoCaptureDevice::GetDeviceSupportedFormats( | 144 void VideoCaptureDevice::GetDeviceSupportedFormats( |
145 const Name& device, | 145 const Name& device, |
146 VideoCaptureFormats* supported_formats) { | 146 VideoCaptureFormats* supported_formats) { |
147 if (device.id().empty()) | 147 if (device.id().empty()) |
148 return; | 148 return; |
149 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))); | 149 int fd; |
150 if (!fd.is_valid()) { | 150 if ((fd = HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))) < 0) { |
151 // Failed to open this device. | 151 // Failed to open this device. |
152 return; | 152 return; |
153 } | 153 } |
| 154 file_util::ScopedFD fd_closer(&fd); |
154 supported_formats->clear(); | 155 supported_formats->clear(); |
155 | 156 |
156 // Retrieve the caps one by one, first get pixel format, then sizes, then | 157 // Retrieve the caps one by one, first get pixel format, then sizes, then |
157 // frame rates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. | 158 // frame rates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. |
158 v4l2_fmtdesc pixel_format = {}; | 159 v4l2_fmtdesc pixel_format = {}; |
159 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 160 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
160 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FMT, &pixel_format)) == 0) { | 161 while (HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format)) == 0) { |
161 VideoCaptureFormat supported_format; | 162 VideoCaptureFormat supported_format; |
162 supported_format.pixel_format = | 163 supported_format.pixel_format = |
163 V4l2ColorToVideoCaptureColorFormat((int32)pixel_format.pixelformat); | 164 V4l2ColorToVideoCaptureColorFormat((int32)pixel_format.pixelformat); |
164 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) { | 165 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) { |
165 ++pixel_format.index; | 166 ++pixel_format.index; |
166 continue; | 167 continue; |
167 } | 168 } |
168 | 169 |
169 v4l2_frmsizeenum frame_size = {}; | 170 v4l2_frmsizeenum frame_size = {}; |
170 frame_size.pixel_format = pixel_format.pixelformat; | 171 frame_size.pixel_format = pixel_format.pixelformat; |
171 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMESIZES, &frame_size)) == | 172 while (HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size)) == 0) { |
172 0) { | |
173 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { | 173 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { |
174 supported_format.frame_size.SetSize( | 174 supported_format.frame_size.SetSize( |
175 frame_size.discrete.width, frame_size.discrete.height); | 175 frame_size.discrete.width, frame_size.discrete.height); |
176 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { | 176 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { |
177 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 177 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
178 NOTIMPLEMENTED(); | 178 NOTIMPLEMENTED(); |
179 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { | 179 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { |
180 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 180 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
181 NOTIMPLEMENTED(); | 181 NOTIMPLEMENTED(); |
182 } | 182 } |
183 v4l2_frmivalenum frame_interval = {}; | 183 v4l2_frmivalenum frame_interval = {}; |
184 frame_interval.pixel_format = pixel_format.pixelformat; | 184 frame_interval.pixel_format = pixel_format.pixelformat; |
185 frame_interval.width = frame_size.discrete.width; | 185 frame_interval.width = frame_size.discrete.width; |
186 frame_interval.height = frame_size.discrete.height; | 186 frame_interval.height = frame_size.discrete.height; |
187 while (HANDLE_EINTR(ioctl( | 187 while (HANDLE_EINTR( |
188 fd.get(), VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) == 0) { | 188 ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) == 0) { |
189 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { | 189 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { |
190 if (frame_interval.discrete.numerator != 0) { | 190 if (frame_interval.discrete.numerator != 0) { |
191 supported_format.frame_rate = | 191 supported_format.frame_rate = |
192 static_cast<float>(frame_interval.discrete.denominator) / | 192 static_cast<float>(frame_interval.discrete.denominator) / |
193 static_cast<float>(frame_interval.discrete.numerator); | 193 static_cast<float>(frame_interval.discrete.numerator); |
194 } else { | 194 } else { |
195 supported_format.frame_rate = 0; | 195 supported_format.frame_rate = 0; |
196 } | 196 } |
197 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { | 197 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { |
198 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 198 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
248 return usb_id; | 248 return usb_id; |
249 } | 249 } |
250 | 250 |
251 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { | 251 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { |
252 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); | 252 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); |
253 if (!self) | 253 if (!self) |
254 return NULL; | 254 return NULL; |
255 // Test opening the device driver. This is to make sure it is available. | 255 // Test opening the device driver. This is to make sure it is available. |
256 // We will reopen it again in our worker thread when someone | 256 // We will reopen it again in our worker thread when someone |
257 // allocates the camera. | 257 // allocates the camera. |
258 base::ScopedFD fd(HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY))); | 258 int fd = HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY)); |
259 if (!fd.is_valid()) { | 259 if (fd < 0) { |
260 DVLOG(1) << "Cannot open device"; | 260 DVLOG(1) << "Cannot open device"; |
261 delete self; | 261 delete self; |
262 return NULL; | 262 return NULL; |
263 } | 263 } |
| 264 close(fd); |
264 | 265 |
265 return self; | 266 return self; |
266 } | 267 } |
267 | 268 |
268 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) | 269 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) |
269 : state_(kIdle), | 270 : state_(kIdle), |
270 device_name_(device_name), | 271 device_name_(device_name), |
| 272 device_fd_(-1), |
271 v4l2_thread_("V4L2Thread"), | 273 v4l2_thread_("V4L2Thread"), |
272 buffer_pool_(NULL), | 274 buffer_pool_(NULL), |
273 buffer_pool_size_(0), | 275 buffer_pool_size_(0), |
274 timeout_count_(0) {} | 276 timeout_count_(0) {} |
275 | 277 |
276 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { | 278 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { |
277 state_ = kIdle; | 279 state_ = kIdle; |
278 // Check if the thread is running. | 280 // Check if the thread is running. |
279 // This means that the device have not been DeAllocated properly. | 281 // This means that the device have not been DeAllocated properly. |
280 DCHECK(!v4l2_thread_.IsRunning()); | 282 DCHECK(!v4l2_thread_.IsRunning()); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 | 317 |
316 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, | 318 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, |
317 int height, | 319 int height, |
318 int frame_rate, | 320 int frame_rate, |
319 scoped_ptr<Client> client) { | 321 scoped_ptr<Client> client) { |
320 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 322 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
321 | 323 |
322 client_ = client.Pass(); | 324 client_ = client.Pass(); |
323 | 325 |
324 // Need to open camera with O_RDWR after Linux kernel 3.3. | 326 // Need to open camera with O_RDWR after Linux kernel 3.3. |
325 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR))); | 327 device_fd_ = HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR)); |
326 if (!device_fd_.is_valid()) { | 328 if (device_fd_ < 0) { |
327 SetErrorState("Failed to open V4L2 device driver."); | 329 SetErrorState("Failed to open V4L2 device driver."); |
328 return; | 330 return; |
329 } | 331 } |
| 332 device_fd_closer_.reset(&device_fd_); |
330 | 333 |
331 // Test if this is a V4L2 capture device. | 334 // Test if this is a V4L2 capture device. |
332 v4l2_capability cap; | 335 v4l2_capability cap; |
333 if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) && | 336 if (!((HANDLE_EINTR(ioctl(device_fd_, VIDIOC_QUERYCAP, &cap)) == 0) && |
334 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && | 337 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && |
335 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) { | 338 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) { |
336 // This is not a V4L2 video capture device. | 339 // This is not a V4L2 video capture device. |
337 device_fd_.reset(); | 340 device_fd_closer_.reset(); |
| 341 device_fd_ = -1; |
338 SetErrorState("This is not a V4L2 video capture device"); | 342 SetErrorState("This is not a V4L2 video capture device"); |
339 return; | 343 return; |
340 } | 344 } |
341 | 345 |
342 // Get supported video formats in preferred order. | 346 // Get supported video formats in preferred order. |
343 // For large resolutions, favour mjpeg over raw formats. | 347 // For large resolutions, favour mjpeg over raw formats. |
344 std::list<int> v4l2_formats; | 348 std::list<int> v4l2_formats; |
345 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight, | 349 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight, |
346 &v4l2_formats); | 350 &v4l2_formats); |
347 | 351 |
348 v4l2_fmtdesc fmtdesc; | 352 v4l2_fmtdesc fmtdesc; |
349 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); | 353 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); |
350 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 354 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
351 | 355 |
352 // Enumerate image formats. | 356 // Enumerate image formats. |
353 std::list<int>::iterator best = v4l2_formats.end(); | 357 std::list<int>::iterator best = v4l2_formats.end(); |
354 while (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == | 358 while (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc)) == 0) { |
355 0) { | |
356 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); | 359 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); |
357 fmtdesc.index++; | 360 fmtdesc.index++; |
358 } | 361 } |
359 | 362 |
360 if (best == v4l2_formats.end()) { | 363 if (best == v4l2_formats.end()) { |
361 SetErrorState("Failed to find a supported camera format."); | 364 SetErrorState("Failed to find a supported camera format."); |
362 return; | 365 return; |
363 } | 366 } |
364 | 367 |
365 // Set format and frame size now. | 368 // Set format and frame size now. |
366 v4l2_format video_fmt; | 369 v4l2_format video_fmt; |
367 memset(&video_fmt, 0, sizeof(video_fmt)); | 370 memset(&video_fmt, 0, sizeof(video_fmt)); |
368 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 371 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
369 video_fmt.fmt.pix.sizeimage = 0; | 372 video_fmt.fmt.pix.sizeimage = 0; |
370 video_fmt.fmt.pix.width = width; | 373 video_fmt.fmt.pix.width = width; |
371 video_fmt.fmt.pix.height = height; | 374 video_fmt.fmt.pix.height = height; |
372 video_fmt.fmt.pix.pixelformat = *best; | 375 video_fmt.fmt.pix.pixelformat = *best; |
373 | 376 |
374 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt)) < 0) { | 377 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_S_FMT, &video_fmt)) < 0) { |
375 SetErrorState("Failed to set camera format"); | 378 SetErrorState("Failed to set camera format"); |
376 return; | 379 return; |
377 } | 380 } |
378 | 381 |
379 // Set capture framerate in the form of capture interval. | 382 // Set capture framerate in the form of capture interval. |
380 v4l2_streamparm streamparm; | 383 v4l2_streamparm streamparm; |
381 memset(&streamparm, 0, sizeof(v4l2_streamparm)); | 384 memset(&streamparm, 0, sizeof(v4l2_streamparm)); |
382 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 385 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
383 // The following line checks that the driver knows about framerate get/set. | 386 // The following line checks that the driver knows about framerate get/set. |
384 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) { | 387 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_G_PARM, &streamparm)) >= 0) { |
385 // Now check if the device is able to accept a capture framerate set. | 388 // Now check if the device is able to accept a capture framerate set. |
386 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { | 389 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { |
387 streamparm.parm.capture.timeperframe.numerator = 1; | 390 streamparm.parm.capture.timeperframe.numerator = 1; |
388 streamparm.parm.capture.timeperframe.denominator = | 391 streamparm.parm.capture.timeperframe.denominator = |
389 (frame_rate) ? frame_rate : kTypicalFramerate; | 392 (frame_rate) ? frame_rate : kTypicalFramerate; |
390 | 393 |
391 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) < | 394 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_S_PARM, &streamparm)) < 0) { |
392 0) { | |
393 SetErrorState("Failed to set camera framerate"); | 395 SetErrorState("Failed to set camera framerate"); |
394 return; | 396 return; |
395 } | 397 } |
396 DVLOG(2) << "Actual camera driverframerate: " | 398 DVLOG(2) << "Actual camera driverframerate: " |
397 << streamparm.parm.capture.timeperframe.denominator << "/" | 399 << streamparm.parm.capture.timeperframe.denominator << "/" |
398 << streamparm.parm.capture.timeperframe.numerator; | 400 << streamparm.parm.capture.timeperframe.numerator; |
399 } | 401 } |
400 } | 402 } |
401 // TODO(mcasas): what should be done if the camera driver does not allow | 403 // TODO(mcasas): what should be done if the camera driver does not allow |
402 // framerate configuration, or the actual one is different from the desired? | 404 // framerate configuration, or the actual one is different from the desired? |
403 | 405 |
404 // Store our current width and height. | 406 // Store our current width and height. |
405 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width, | 407 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width, |
406 video_fmt.fmt.pix.height); | 408 video_fmt.fmt.pix.height); |
407 capture_format_.frame_rate = frame_rate; | 409 capture_format_.frame_rate = frame_rate; |
408 capture_format_.pixel_format = | 410 capture_format_.pixel_format = |
409 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat); | 411 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat); |
410 | 412 |
411 // Start capturing. | 413 // Start capturing. |
412 if (!AllocateVideoBuffers()) { | 414 if (!AllocateVideoBuffers()) { |
413 // Error, We can not recover. | 415 // Error, We can not recover. |
414 SetErrorState("Allocate buffer failed"); | 416 SetErrorState("Allocate buffer failed"); |
415 return; | 417 return; |
416 } | 418 } |
417 | 419 |
418 // Start UVC camera. | 420 // Start UVC camera. |
419 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 421 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
420 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) == -1) { | 422 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_STREAMON, &type)) == -1) { |
421 SetErrorState("VIDIOC_STREAMON failed"); | 423 SetErrorState("VIDIOC_STREAMON failed"); |
422 return; | 424 return; |
423 } | 425 } |
424 | 426 |
425 state_ = kCapturing; | 427 state_ = kCapturing; |
426 // Post task to start fetching frames from v4l2. | 428 // Post task to start fetching frames from v4l2. |
427 v4l2_thread_.message_loop()->PostTask( | 429 v4l2_thread_.message_loop()->PostTask( |
428 FROM_HERE, | 430 FROM_HERE, |
429 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, | 431 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, |
430 base::Unretained(this))); | 432 base::Unretained(this))); |
431 } | 433 } |
432 | 434 |
433 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() { | 435 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() { |
434 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 436 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
435 | 437 |
436 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 438 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
437 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) { | 439 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_STREAMOFF, &type)) < 0) { |
438 SetErrorState("VIDIOC_STREAMOFF failed"); | 440 SetErrorState("VIDIOC_STREAMOFF failed"); |
439 return; | 441 return; |
440 } | 442 } |
441 // We don't dare to deallocate the buffers if we can't stop | 443 // We don't dare to deallocate the buffers if we can't stop |
442 // the capture device. | 444 // the capture device. |
443 DeAllocateVideoBuffers(); | 445 DeAllocateVideoBuffers(); |
444 | 446 |
445 // We need to close and open the device if we want to change the settings | 447 // We need to close and open the device if we want to change the settings |
446 // Otherwise VIDIOC_S_FMT will return error | 448 // Otherwise VIDIOC_S_FMT will return error |
447 // Sad but true. | 449 // Sad but true. |
448 device_fd_.reset(); | 450 device_fd_closer_.reset(); |
| 451 device_fd_ = -1; |
449 state_ = kIdle; | 452 state_ = kIdle; |
450 client_.reset(); | 453 client_.reset(); |
451 } | 454 } |
452 | 455 |
453 void VideoCaptureDeviceLinux::OnCaptureTask() { | 456 void VideoCaptureDeviceLinux::OnCaptureTask() { |
454 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 457 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
455 | 458 |
456 if (state_ != kCapturing) { | 459 if (state_ != kCapturing) { |
457 return; | 460 return; |
458 } | 461 } |
459 | 462 |
460 fd_set r_set; | 463 fd_set r_set; |
461 FD_ZERO(&r_set); | 464 FD_ZERO(&r_set); |
462 FD_SET(device_fd_.get(), &r_set); | 465 FD_SET(device_fd_, &r_set); |
463 timeval timeout; | 466 timeval timeout; |
464 | 467 |
465 timeout.tv_sec = 0; | 468 timeout.tv_sec = 0; |
466 timeout.tv_usec = kCaptureTimeoutUs; | 469 timeout.tv_usec = kCaptureTimeoutUs; |
467 | 470 |
468 // First argument to select is the highest numbered file descriptor +1. | 471 // First argument to select is the highest numbered file descriptor +1. |
469 // Refer to http://linux.die.net/man/2/select for more information. | 472 // Refer to http://linux.die.net/man/2/select for more information. |
470 int result = | 473 int result = |
471 HANDLE_EINTR(select(device_fd_.get() + 1, &r_set, NULL, NULL, &timeout)); | 474 HANDLE_EINTR(select(device_fd_ + 1, &r_set, NULL, NULL, &timeout)); |
472 // Check if select have failed. | 475 // Check if select have failed. |
473 if (result < 0) { | 476 if (result < 0) { |
474 // EINTR is a signal. This is not really an error. | 477 // EINTR is a signal. This is not really an error. |
475 if (errno != EINTR) { | 478 if (errno != EINTR) { |
476 SetErrorState("Select failed"); | 479 SetErrorState("Select failed"); |
477 return; | 480 return; |
478 } | 481 } |
479 v4l2_thread_.message_loop()->PostDelayedTask( | 482 v4l2_thread_.message_loop()->PostDelayedTask( |
480 FROM_HERE, | 483 FROM_HERE, |
481 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, | 484 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, |
482 base::Unretained(this)), | 485 base::Unretained(this)), |
483 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs)); | 486 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs)); |
484 } | 487 } |
485 | 488 |
486 // Check if select timeout. | 489 // Check if select timeout. |
487 if (result == 0) { | 490 if (result == 0) { |
488 timeout_count_++; | 491 timeout_count_++; |
489 if (timeout_count_ >= kContinuousTimeoutLimit) { | 492 if (timeout_count_ >= kContinuousTimeoutLimit) { |
490 SetErrorState(base::StringPrintf( | 493 SetErrorState(base::StringPrintf( |
491 "Continuous timeout %d times", timeout_count_)); | 494 "Continuous timeout %d times", timeout_count_)); |
492 timeout_count_ = 0; | 495 timeout_count_ = 0; |
493 return; | 496 return; |
494 } | 497 } |
495 } else { | 498 } else { |
496 timeout_count_ = 0; | 499 timeout_count_ = 0; |
497 } | 500 } |
498 | 501 |
499 // Check if the driver have filled a buffer. | 502 // Check if the driver have filled a buffer. |
500 if (FD_ISSET(device_fd_.get(), &r_set)) { | 503 if (FD_ISSET(device_fd_, &r_set)) { |
501 v4l2_buffer buffer; | 504 v4l2_buffer buffer; |
502 memset(&buffer, 0, sizeof(buffer)); | 505 memset(&buffer, 0, sizeof(buffer)); |
503 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 506 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
504 buffer.memory = V4L2_MEMORY_MMAP; | 507 buffer.memory = V4L2_MEMORY_MMAP; |
505 // Dequeue a buffer. | 508 // Dequeue a buffer. |
506 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) { | 509 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_DQBUF, &buffer)) == 0) { |
507 client_->OnIncomingCapturedData( | 510 client_->OnIncomingCapturedData( |
508 static_cast<uint8*>(buffer_pool_[buffer.index].start), | 511 static_cast<uint8*>(buffer_pool_[buffer.index].start), |
509 buffer.bytesused, | 512 buffer.bytesused, |
510 capture_format_, | 513 capture_format_, |
511 0, | 514 0, |
512 base::TimeTicks::Now()); | 515 base::TimeTicks::Now()); |
513 | 516 |
514 // Enqueue the buffer again. | 517 // Enqueue the buffer again. |
515 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) { | 518 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_QBUF, &buffer)) == -1) { |
516 SetErrorState(base::StringPrintf( | 519 SetErrorState(base::StringPrintf( |
517 "Failed to enqueue capture buffer errno %d", errno)); | 520 "Failed to enqueue capture buffer errno %d", errno)); |
518 } | 521 } |
519 } else { | 522 } else { |
520 SetErrorState(base::StringPrintf( | 523 SetErrorState(base::StringPrintf( |
521 "Failed to dequeue capture buffer errno %d", errno)); | 524 "Failed to dequeue capture buffer errno %d", errno)); |
522 return; | 525 return; |
523 } | 526 } |
524 } | 527 } |
525 | 528 |
526 v4l2_thread_.message_loop()->PostTask( | 529 v4l2_thread_.message_loop()->PostTask( |
527 FROM_HERE, | 530 FROM_HERE, |
528 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, | 531 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, |
529 base::Unretained(this))); | 532 base::Unretained(this))); |
530 } | 533 } |
531 | 534 |
532 bool VideoCaptureDeviceLinux::AllocateVideoBuffers() { | 535 bool VideoCaptureDeviceLinux::AllocateVideoBuffers() { |
533 v4l2_requestbuffers r_buffer; | 536 v4l2_requestbuffers r_buffer; |
534 memset(&r_buffer, 0, sizeof(r_buffer)); | 537 memset(&r_buffer, 0, sizeof(r_buffer)); |
535 | 538 |
536 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 539 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
537 r_buffer.memory = V4L2_MEMORY_MMAP; | 540 r_buffer.memory = V4L2_MEMORY_MMAP; |
538 r_buffer.count = kMaxVideoBuffers; | 541 r_buffer.count = kMaxVideoBuffers; |
539 | 542 |
540 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) { | 543 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer)) < 0) { |
541 return false; | 544 return false; |
542 } | 545 } |
543 | 546 |
544 if (r_buffer.count > kMaxVideoBuffers) { | 547 if (r_buffer.count > kMaxVideoBuffers) { |
545 r_buffer.count = kMaxVideoBuffers; | 548 r_buffer.count = kMaxVideoBuffers; |
546 } | 549 } |
547 | 550 |
548 buffer_pool_size_ = r_buffer.count; | 551 buffer_pool_size_ = r_buffer.count; |
549 | 552 |
550 // Map the buffers. | 553 // Map the buffers. |
551 buffer_pool_ = new Buffer[r_buffer.count]; | 554 buffer_pool_ = new Buffer[r_buffer.count]; |
552 for (unsigned int i = 0; i < r_buffer.count; i++) { | 555 for (unsigned int i = 0; i < r_buffer.count; i++) { |
553 v4l2_buffer buffer; | 556 v4l2_buffer buffer; |
554 memset(&buffer, 0, sizeof(buffer)); | 557 memset(&buffer, 0, sizeof(buffer)); |
555 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 558 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
556 buffer.memory = V4L2_MEMORY_MMAP; | 559 buffer.memory = V4L2_MEMORY_MMAP; |
557 buffer.index = i; | 560 buffer.index = i; |
558 | 561 |
559 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) { | 562 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_QUERYBUF, &buffer)) < 0) { |
560 return false; | 563 return false; |
561 } | 564 } |
562 | 565 |
563 // Some devices require mmap() to be called with both READ and WRITE. | 566 // Some devices require mmap() to be called with both READ and WRITE. |
564 // See crbug.com/178582. | 567 // See crbug.com/178582. |
565 buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, | 568 buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, |
566 MAP_SHARED, device_fd_.get(), buffer.m.offset); | 569 MAP_SHARED, device_fd_, buffer.m.offset); |
567 if (buffer_pool_[i].start == MAP_FAILED) { | 570 if (buffer_pool_[i].start == MAP_FAILED) { |
568 return false; | 571 return false; |
569 } | 572 } |
570 buffer_pool_[i].length = buffer.length; | 573 buffer_pool_[i].length = buffer.length; |
571 // Enqueue the buffer in the drivers incoming queue. | 574 // Enqueue the buffer in the drivers incoming queue. |
572 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) { | 575 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_QBUF, &buffer)) < 0) { |
573 return false; | 576 return false; |
574 } | 577 } |
575 } | 578 } |
576 return true; | 579 return true; |
577 } | 580 } |
578 | 581 |
579 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() { | 582 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() { |
580 if (!buffer_pool_) | 583 if (!buffer_pool_) |
581 return; | 584 return; |
582 | 585 |
583 // Unmaps buffers. | 586 // Unmaps buffers. |
584 for (int i = 0; i < buffer_pool_size_; i++) { | 587 for (int i = 0; i < buffer_pool_size_; i++) { |
585 munmap(buffer_pool_[i].start, buffer_pool_[i].length); | 588 munmap(buffer_pool_[i].start, buffer_pool_[i].length); |
586 } | 589 } |
587 v4l2_requestbuffers r_buffer; | 590 v4l2_requestbuffers r_buffer; |
588 memset(&r_buffer, 0, sizeof(r_buffer)); | 591 memset(&r_buffer, 0, sizeof(r_buffer)); |
589 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 592 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
590 r_buffer.memory = V4L2_MEMORY_MMAP; | 593 r_buffer.memory = V4L2_MEMORY_MMAP; |
591 r_buffer.count = 0; | 594 r_buffer.count = 0; |
592 | 595 |
593 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) { | 596 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer)) < 0) { |
594 SetErrorState("Failed to reset buf."); | 597 SetErrorState("Failed to reset buf."); |
595 } | 598 } |
596 | 599 |
597 delete [] buffer_pool_; | 600 delete [] buffer_pool_; |
598 buffer_pool_ = NULL; | 601 buffer_pool_ = NULL; |
599 buffer_pool_size_ = 0; | 602 buffer_pool_size_ = 0; |
600 } | 603 } |
601 | 604 |
602 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { | 605 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { |
603 DCHECK(!v4l2_thread_.IsRunning() || | 606 DCHECK(!v4l2_thread_.IsRunning() || |
604 v4l2_thread_.message_loop() == base::MessageLoop::current()); | 607 v4l2_thread_.message_loop() == base::MessageLoop::current()); |
605 DVLOG(1) << reason; | 608 DVLOG(1) << reason; |
606 state_ = kError; | 609 state_ = kError; |
607 client_->OnError(reason); | 610 client_->OnError(reason); |
608 } | 611 } |
609 | 612 |
610 } // namespace media | 613 } // namespace media |
OLD | NEW |