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