Chromium Code Reviews| 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 #include <poll.h> | 9 #include <poll.h> |
| 10 #if defined(OS_OPENBSD) | 10 #if defined(OS_OPENBSD) |
| 11 #include <sys/videoio.h> | 11 #include <sys/videoio.h> |
| 12 #else | 12 #else |
| 13 #include <linux/videodev2.h> | 13 #include <linux/videodev2.h> |
| 14 #endif | 14 #endif |
| 15 #include <sys/ioctl.h> | 15 #include <sys/ioctl.h> |
| 16 #include <sys/mman.h> | 16 #include <sys/mman.h> |
| 17 | 17 |
| 18 #include <list> | 18 #include <list> |
| 19 #include <string> | 19 #include <string> |
| 20 | 20 |
| 21 #include "base/bind.h" | 21 #include "base/bind.h" |
| 22 #include "base/files/file_enumerator.h" | 22 #include "base/files/file_enumerator.h" |
| 23 #include "base/files/scoped_file.h" | 23 #include "base/files/scoped_file.h" |
| 24 #include "base/posix/eintr_wrapper.h" | 24 #include "base/posix/eintr_wrapper.h" |
| 25 #include "base/strings/stringprintf.h" | 25 #include "base/strings/stringprintf.h" |
| 26 | 26 |
| 27 namespace media { | 27 namespace media { |
| 28 | 28 |
| 29 #define GET_V4L2_FOURCC_CHAR(a, index) ((char)( ((a) >> (8 * index)) & 0xff)) | |
| 30 | |
| 29 // Max number of video buffers VideoCaptureDeviceLinux can allocate. | 31 // Max number of video buffers VideoCaptureDeviceLinux can allocate. |
| 30 enum { kMaxVideoBuffers = 2 }; | 32 enum { kMaxVideoBuffers = 2 }; |
| 31 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw. | 33 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw. |
| 32 enum { kCaptureTimeoutMs = 200 }; | 34 enum { kCaptureTimeoutMs = 200 }; |
| 33 // The number of continuous timeouts tolerated before treated as error. | 35 // The number of continuous timeouts tolerated before treated as error. |
| 34 enum { kContinuousTimeoutLimit = 10 }; | 36 enum { kContinuousTimeoutLimit = 10 }; |
| 35 // MJPEG is preferred if the width or height is larger than this. | 37 // MJPEG is preferred if the width or height is larger than this. |
| 36 enum { kMjpegWidth = 640 }; | 38 enum { kMjpegWidth = 640 }; |
| 37 enum { kMjpegHeight = 480 }; | 39 enum { kMjpegHeight = 480 }; |
| 38 // Typical framerate, in fps | 40 // Typical framerate, in fps |
| 39 enum { kTypicalFramerate = 30 }; | 41 enum { kTypicalFramerate = 30 }; |
| 40 | 42 |
| 41 // V4L2 color formats VideoCaptureDeviceLinux support. | 43 // V4L2 color formats VideoCaptureDeviceLinux support. |
| 42 static const int32 kV4l2RawFmts[] = { | 44 static const int32 kV4l2RawFmts[] = { |
| 43 V4L2_PIX_FMT_YUV420, | 45 V4L2_PIX_FMT_YUV420, |
| 44 V4L2_PIX_FMT_YUYV, | 46 V4L2_PIX_FMT_YUYV, |
| 45 V4L2_PIX_FMT_UYVY | 47 V4L2_PIX_FMT_UYVY |
| 46 }; | 48 }; |
| 47 | 49 |
| 48 // USB VID and PID are both 4 bytes long. | 50 // USB VID and PID are both 4 bytes long. |
| 49 static const size_t kVidPidSize = 4; | 51 static const size_t kVidPidSize = 4; |
| 50 | 52 |
| 51 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding | 53 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding |
| 52 // USB device info directory. | 54 // USB device info directory. |
| 53 static const char kVidPathTemplate[] = | 55 static const char kVidPathTemplate[] = |
| 54 "/sys/class/video4linux/%s/device/../idVendor"; | 56 "/sys/class/video4linux/%s/device/../idVendor"; |
| 55 static const char kPidPathTemplate[] = | 57 static const char kPidPathTemplate[] = |
| 56 "/sys/class/video4linux/%s/device/../idProduct"; | 58 "/sys/class/video4linux/%s/device/../idProduct"; |
| 57 | 59 |
| 58 bool ReadIdFile(const std::string path, std::string* id) { | 60 static bool ReadIdFile(const std::string path, std::string* id) { |
| 59 char id_buf[kVidPidSize]; | 61 char id_buf[kVidPidSize]; |
| 60 FILE* file = fopen(path.c_str(), "rb"); | 62 FILE* file = fopen(path.c_str(), "rb"); |
| 61 if (!file) | 63 if (!file) |
| 62 return false; | 64 return false; |
| 63 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1; | 65 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1; |
| 64 fclose(file); | 66 fclose(file); |
| 65 if (!success) | 67 if (!success) |
| 66 return false; | 68 return false; |
| 67 id->append(id_buf, kVidPidSize); | 69 id->append(id_buf, kVidPidSize); |
| 68 return true; | 70 return true; |
| 69 } | 71 } |
| 70 | 72 |
| 73 //static | |
| 74 int VideoCaptureDeviceLinux::Ioctl(const base::ScopedFD& device_fd, | |
| 75 int request, | |
| 76 void* arg) { | |
| 77 return HANDLE_EINTR(ioctl(device_fd.get(), request, arg)); | |
|
perkj_chrome
2014/12/16 10:34:43
I think this is less readable than calling HANDLE_
mcasas
2014/12/16 18:08:17
Reverted then.
Just FTR I'd say it was cleaner to
| |
| 78 } | |
| 79 | |
| 71 // This function translates Video4Linux pixel formats to Chromium pixel formats, | 80 // This function translates Video4Linux pixel formats to Chromium pixel formats, |
| 72 // should only support those listed in GetListOfUsableFourCCs. | 81 // should only support those listed in GetListOfUsableFourCCs. |
| 73 // static | 82 // static |
| 74 VideoPixelFormat VideoCaptureDeviceLinux::V4l2ColorToVideoCaptureColorFormat( | 83 VideoPixelFormat VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( |
| 75 int32 v4l2_fourcc) { | 84 uint32 v4l2_fourcc) { |
| 76 VideoPixelFormat result = PIXEL_FORMAT_UNKNOWN; | 85 VideoPixelFormat result = PIXEL_FORMAT_UNKNOWN; |
| 77 switch (v4l2_fourcc) { | 86 switch (v4l2_fourcc) { |
| 78 case V4L2_PIX_FMT_YUV420: | 87 case V4L2_PIX_FMT_YUV420: |
| 79 result = PIXEL_FORMAT_I420; | 88 result = PIXEL_FORMAT_I420; |
| 80 break; | 89 break; |
| 81 case V4L2_PIX_FMT_YUYV: | 90 case V4L2_PIX_FMT_YUYV: |
| 82 result = PIXEL_FORMAT_YUY2; | 91 result = PIXEL_FORMAT_YUY2; |
| 83 break; | 92 break; |
| 84 case V4L2_PIX_FMT_UYVY: | 93 case V4L2_PIX_FMT_UYVY: |
| 85 result = PIXEL_FORMAT_UYVY; | 94 result = PIXEL_FORMAT_UYVY; |
| 86 break; | 95 break; |
| 87 case V4L2_PIX_FMT_MJPEG: | 96 case V4L2_PIX_FMT_MJPEG: |
| 88 case V4L2_PIX_FMT_JPEG: | 97 case V4L2_PIX_FMT_JPEG: |
| 89 result = PIXEL_FORMAT_MJPEG; | 98 result = PIXEL_FORMAT_MJPEG; |
| 90 break; | 99 break; |
| 91 default: | 100 default: |
| 92 DVLOG(1) << "Unsupported pixel format " << std::hex << v4l2_fourcc; | 101 DVLOG(1) << "Unsupported pixel format: " |
| 102 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 0) | |
| 103 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 1) | |
| 104 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 2) | |
| 105 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 3); | |
| 93 } | 106 } |
| 94 return result; | 107 return result; |
| 95 } | 108 } |
| 96 | 109 |
| 97 // static | 110 // static |
| 98 void VideoCaptureDeviceLinux::GetListOfUsableFourCCs(bool favour_mjpeg, | 111 std::list<int> VideoCaptureDeviceLinux::GetListOfUsableFourCCs( |
| 99 std::list<int>* fourccs) { | 112 bool favour_mjpeg) { |
| 113 std::list<int> fourccs; | |
| 100 for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i) | 114 for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i) |
| 101 fourccs->push_back(kV4l2RawFmts[i]); | 115 fourccs.push_back(kV4l2RawFmts[i]); |
| 102 if (favour_mjpeg) | 116 if (favour_mjpeg) |
| 103 fourccs->push_front(V4L2_PIX_FMT_MJPEG); | 117 fourccs.push_front(V4L2_PIX_FMT_MJPEG); |
| 104 else | 118 else |
| 105 fourccs->push_back(V4L2_PIX_FMT_MJPEG); | 119 fourccs.push_back(V4L2_PIX_FMT_MJPEG); |
| 106 | 120 |
| 107 // JPEG works as MJPEG on some gspca webcams from field reports. | 121 // JPEG works as MJPEG on some gspca webcams from field reports. |
| 108 // Put it as the least preferred format. | 122 // Put it as the least preferred format. |
| 109 fourccs->push_back(V4L2_PIX_FMT_JPEG); | 123 fourccs.push_back(V4L2_PIX_FMT_JPEG); |
| 124 return fourccs; | |
| 110 } | 125 } |
| 111 | 126 |
| 112 const std::string VideoCaptureDevice::Name::GetModel() const { | 127 const std::string VideoCaptureDevice::Name::GetModel() const { |
| 113 // |unique_id| is of the form "/dev/video2". |file_name| is "video2". | 128 // |unique_id| is of the form "/dev/video2". |file_name| is "video2". |
| 114 const std::string dev_dir = "/dev/"; | 129 const std::string dev_dir = "/dev/"; |
| 115 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir)); | 130 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir)); |
| 116 const std::string file_name = | 131 const std::string file_name = |
| 117 unique_id_.substr(dev_dir.length(), unique_id_.length()); | 132 unique_id_.substr(dev_dir.length(), unique_id_.length()); |
| 118 | 133 |
| 119 const std::string vidPath = | 134 const std::string vidPath = |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 | 224 |
| 210 // Need to open camera with O_RDWR after Linux kernel 3.3. | 225 // Need to open camera with O_RDWR after Linux kernel 3.3. |
| 211 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR))); | 226 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR))); |
| 212 if (!device_fd_.is_valid()) { | 227 if (!device_fd_.is_valid()) { |
| 213 SetErrorState("Failed to open V4L2 device driver."); | 228 SetErrorState("Failed to open V4L2 device driver."); |
| 214 return; | 229 return; |
| 215 } | 230 } |
| 216 | 231 |
| 217 // Test if this is a V4L2 capture device. | 232 // Test if this is a V4L2 capture device. |
| 218 v4l2_capability cap; | 233 v4l2_capability cap; |
| 219 if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) && | 234 if (!((Ioctl(device_fd_, VIDIOC_QUERYCAP, &cap) == 0) && |
| 220 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && | 235 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && |
| 221 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) { | 236 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) { |
| 222 // This is not a V4L2 video capture device. | 237 // This is not a V4L2 video capture device. |
| 223 device_fd_.reset(); | 238 device_fd_.reset(); |
| 224 SetErrorState("This is not a V4L2 video capture device"); | 239 SetErrorState("This is not a V4L2 video capture device"); |
| 225 return; | 240 return; |
| 226 } | 241 } |
| 227 | 242 |
| 228 // Get supported video formats in preferred order. | 243 // Get supported video formats in preferred order. |
| 229 // For large resolutions, favour mjpeg over raw formats. | 244 // For large resolutions, favour mjpeg over raw formats. |
| 230 std::list<int> v4l2_formats; | 245 const std::list<int>& desired_v4l2_formats = |
| 231 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight, | 246 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight); |
| 232 &v4l2_formats); | 247 std::list<int>::const_iterator best = desired_v4l2_formats.end(); |
| 233 | 248 |
| 234 v4l2_fmtdesc fmtdesc = {0}; | 249 v4l2_fmtdesc fmtdesc = {0}; |
| 235 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 250 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 236 | 251 for (; Ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc) == 0; ++fmtdesc.index) { |
| 237 // Enumerate image formats. | 252 best = std::find(desired_v4l2_formats.begin(), best, fmtdesc.pixelformat); |
| 238 std::list<int>::iterator best = v4l2_formats.end(); | |
| 239 while (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == | |
| 240 0) { | |
| 241 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); | |
| 242 fmtdesc.index++; | |
| 243 } | 253 } |
| 244 | 254 if (best == desired_v4l2_formats.end()) { |
| 245 if (best == v4l2_formats.end()) { | |
| 246 SetErrorState("Failed to find a supported camera format."); | 255 SetErrorState("Failed to find a supported camera format."); |
| 247 return; | 256 return; |
| 248 } | 257 } |
| 249 | 258 |
| 250 // Set format and frame size now. | 259 // Set format and frame size now. |
| 251 v4l2_format video_fmt; | 260 v4l2_format video_fmt; |
| 252 memset(&video_fmt, 0, sizeof(v4l2_format)); | 261 memset(&video_fmt, 0, sizeof(v4l2_format)); |
| 253 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 262 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 254 video_fmt.fmt.pix.sizeimage = 0; | 263 video_fmt.fmt.pix.sizeimage = 0; |
| 255 video_fmt.fmt.pix.width = width; | 264 video_fmt.fmt.pix.width = width; |
| 256 video_fmt.fmt.pix.height = height; | 265 video_fmt.fmt.pix.height = height; |
| 257 video_fmt.fmt.pix.pixelformat = *best; | 266 video_fmt.fmt.pix.pixelformat = *best; |
| 258 | 267 |
| 259 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt)) < 0) { | 268 if (Ioctl(device_fd_, VIDIOC_S_FMT, &video_fmt) < 0) { |
| 260 SetErrorState( | 269 SetErrorState( |
| 261 base::StringPrintf("Failed to set camera format: %s", strerror(errno))); | 270 base::StringPrintf("Failed to set camera format: %s", strerror(errno))); |
| 262 return; | 271 return; |
| 263 } | 272 } |
| 264 | 273 |
| 265 // Set capture framerate in the form of capture interval. | 274 // Set capture framerate in the form of capture interval. |
| 266 v4l2_streamparm streamparm; | 275 v4l2_streamparm streamparm; |
| 267 memset(&streamparm, 0, sizeof(v4l2_streamparm)); | 276 memset(&streamparm, 0, sizeof(v4l2_streamparm)); |
| 268 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 277 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 269 // The following line checks that the driver knows about framerate get/set. | 278 // The following line checks that the driver knows about framerate get/set. |
| 270 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) { | 279 if (Ioctl(device_fd_, VIDIOC_G_PARM, &streamparm) >= 0) { |
| 271 // Now check if the device is able to accept a capture framerate set. | 280 // Now check if the device is able to accept a capture framerate set. |
| 272 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { | 281 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { |
| 273 // |frame_rate| is float, approximate by a fraction. | 282 // |frame_rate| is float, approximate by a fraction. |
| 274 streamparm.parm.capture.timeperframe.numerator = | 283 streamparm.parm.capture.timeperframe.numerator = |
| 275 media::kFrameRatePrecision; | 284 media::kFrameRatePrecision; |
| 276 streamparm.parm.capture.timeperframe.denominator = (frame_rate) ? | 285 streamparm.parm.capture.timeperframe.denominator = (frame_rate) ? |
| 277 (frame_rate * media::kFrameRatePrecision) : | 286 (frame_rate * media::kFrameRatePrecision) : |
| 278 (kTypicalFramerate * media::kFrameRatePrecision); | 287 (kTypicalFramerate * media::kFrameRatePrecision); |
| 279 | 288 |
| 280 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) < | 289 if (Ioctl(device_fd_, VIDIOC_S_PARM, &streamparm) < 0) { |
| 281 0) { | |
| 282 SetErrorState("Failed to set camera framerate"); | 290 SetErrorState("Failed to set camera framerate"); |
| 283 return; | 291 return; |
| 284 } | 292 } |
| 285 DVLOG(2) << "Actual camera driverframerate: " | 293 DVLOG(2) << "Actual camera driverframerate: " |
| 286 << streamparm.parm.capture.timeperframe.denominator << "/" | 294 << streamparm.parm.capture.timeperframe.denominator << "/" |
| 287 << streamparm.parm.capture.timeperframe.numerator; | 295 << streamparm.parm.capture.timeperframe.numerator; |
| 288 } | 296 } |
| 289 } | 297 } |
| 290 // TODO(mcasas): what should be done if the camera driver does not allow | 298 // TODO(mcasas): what should be done if the camera driver does not allow |
| 291 // framerate configuration, or the actual one is different from the desired? | 299 // framerate configuration, or the actual one is different from the desired? |
| 292 | 300 |
| 293 // Set anti-banding/anti-flicker to 50/60Hz. May fail due to not supported | 301 // Set anti-banding/anti-flicker to 50/60Hz. May fail due to not supported |
| 294 // operation (|errno| == EINVAL in this case) or plain failure. | 302 // operation (|errno| == EINVAL in this case) or plain failure. |
| 295 const int power_line_frequency = GetPowerLineFrequencyForLocation(); | 303 const int power_line_frequency = GetPowerLineFrequencyForLocation(); |
| 296 if ((power_line_frequency == kPowerLine50Hz) || | 304 if ((power_line_frequency == kPowerLine50Hz) || |
| 297 (power_line_frequency == kPowerLine60Hz)) { | 305 (power_line_frequency == kPowerLine60Hz)) { |
| 298 struct v4l2_control control = {}; | 306 struct v4l2_control control = {}; |
| 299 control.id = V4L2_CID_POWER_LINE_FREQUENCY; | 307 control.id = V4L2_CID_POWER_LINE_FREQUENCY; |
| 300 control.value = (power_line_frequency == kPowerLine50Hz) ? | 308 control.value = (power_line_frequency == kPowerLine50Hz) ? |
| 301 V4L2_CID_POWER_LINE_FREQUENCY_50HZ : | 309 V4L2_CID_POWER_LINE_FREQUENCY_50HZ : |
| 302 V4L2_CID_POWER_LINE_FREQUENCY_60HZ; | 310 V4L2_CID_POWER_LINE_FREQUENCY_60HZ; |
| 303 HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control)); | 311 HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control)); |
| 304 } | 312 } |
| 305 | 313 |
| 306 // Store our current width and height. | 314 // Store our current width and height. |
| 307 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width, | 315 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width, |
| 308 video_fmt.fmt.pix.height); | 316 video_fmt.fmt.pix.height); |
| 309 capture_format_.frame_rate = frame_rate; | 317 capture_format_.frame_rate = frame_rate; |
| 310 capture_format_.pixel_format = | 318 capture_format_.pixel_format = |
| 311 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat); | 319 V4l2FourCcToChromiumPixelFormat(video_fmt.fmt.pix.pixelformat); |
| 312 | 320 |
| 313 // Start capturing. | |
| 314 if (!AllocateVideoBuffers()) { | 321 if (!AllocateVideoBuffers()) { |
| 315 // Error, We can not recover. | 322 SetErrorState("Allocate buffers failed"); |
| 316 SetErrorState("Allocate buffer failed"); | |
| 317 return; | 323 return; |
| 318 } | 324 } |
| 319 | 325 |
| 320 // Start UVC camera. | 326 // Start UVC camera. |
| 321 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 327 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 322 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) == -1) { | 328 if (Ioctl(device_fd_, VIDIOC_STREAMON, &type) == -1) { |
| 323 SetErrorState("VIDIOC_STREAMON failed"); | 329 SetErrorState("VIDIOC_STREAMON failed"); |
| 324 return; | 330 return; |
| 325 } | 331 } |
| 326 | 332 |
| 327 is_capturing_ = true; | 333 is_capturing_ = true; |
| 328 // Post task to start fetching frames from v4l2. | 334 // Post task to start fetching frames from v4l2. |
| 329 v4l2_thread_.message_loop()->PostTask( | 335 v4l2_thread_.message_loop()->PostTask( |
| 330 FROM_HERE, | 336 FROM_HERE, |
| 331 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, | 337 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, |
| 332 base::Unretained(this))); | 338 base::Unretained(this))); |
| 333 } | 339 } |
| 334 | 340 |
| 335 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() { | 341 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() { |
| 336 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 342 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
| 337 | 343 |
| 338 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 344 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 339 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) { | 345 if (Ioctl(device_fd_, VIDIOC_STREAMOFF, &type) < 0) { |
| 340 SetErrorState("VIDIOC_STREAMOFF failed"); | 346 SetErrorState("VIDIOC_STREAMOFF failed"); |
| 341 return; | 347 return; |
| 342 } | 348 } |
| 343 // We don't dare to deallocate the buffers if we can't stop | 349 // We don't dare to deallocate the buffers if we can't stop the capture |
| 344 // the capture device. | 350 // device. |
| 345 DeAllocateVideoBuffers(); | 351 DeAllocateVideoBuffers(); |
| 346 | 352 |
| 347 // We need to close and open the device if we want to change the settings | 353 // We need to close and open the device if we want to change the settings. |
| 348 // Otherwise VIDIOC_S_FMT will return error | 354 // Otherwise VIDIOC_S_FMT will return error. Sad but true. |
| 349 // Sad but true. | |
| 350 device_fd_.reset(); | 355 device_fd_.reset(); |
| 351 is_capturing_ = false; | 356 is_capturing_ = false; |
| 352 client_.reset(); | 357 client_.reset(); |
| 353 } | 358 } |
| 354 | 359 |
| 355 void VideoCaptureDeviceLinux::OnCaptureTask() { | 360 void VideoCaptureDeviceLinux::OnCaptureTask() { |
| 356 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); | 361 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); |
| 357 if (!is_capturing_) | 362 if (!is_capturing_) |
| 358 return; | 363 return; |
| 359 | 364 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 380 | 385 |
| 381 timeout_count_ = 0; | 386 timeout_count_ = 0; |
| 382 | 387 |
| 383 // Check if the driver has filled a buffer. | 388 // Check if the driver has filled a buffer. |
| 384 if (device_pfd.revents & POLLIN) { | 389 if (device_pfd.revents & POLLIN) { |
| 385 v4l2_buffer buffer; | 390 v4l2_buffer buffer; |
| 386 memset(&buffer, 0, sizeof(buffer)); | 391 memset(&buffer, 0, sizeof(buffer)); |
| 387 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 392 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 388 buffer.memory = V4L2_MEMORY_MMAP; | 393 buffer.memory = V4L2_MEMORY_MMAP; |
| 389 // Dequeue a buffer. | 394 // Dequeue a buffer. |
| 390 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) { | 395 if (Ioctl(device_fd_, VIDIOC_DQBUF, &buffer) == 0) { |
| 391 client_->OnIncomingCapturedData( | 396 client_->OnIncomingCapturedData( |
| 392 static_cast<uint8*>(buffer_pool_[buffer.index].start), | 397 static_cast<uint8*>(buffer_pool_[buffer.index].start), |
| 393 buffer.bytesused, | 398 buffer.bytesused, |
| 394 capture_format_, | 399 capture_format_, |
| 395 rotation_, | 400 rotation_, |
| 396 base::TimeTicks::Now()); | 401 base::TimeTicks::Now()); |
| 397 | 402 |
| 398 // Enqueue the buffer again. | 403 // Enqueue the buffer again. |
| 399 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) { | 404 if (Ioctl(device_fd_, VIDIOC_QBUF, &buffer) == -1) { |
| 400 SetErrorState(base::StringPrintf( | 405 SetErrorState(base::StringPrintf( |
| 401 "Failed to enqueue capture buffer errno %d", errno)); | 406 "Failed to enqueue capture buffer errno %d", errno)); |
| 402 } | 407 } |
| 403 } else { | 408 } else { |
| 404 SetErrorState(base::StringPrintf( | 409 SetErrorState(base::StringPrintf( |
| 405 "Failed to dequeue capture buffer errno %d", errno)); | 410 "Failed to dequeue capture buffer errno %d", errno)); |
| 406 return; | 411 return; |
| 407 } | 412 } |
| 408 } | 413 } |
| 409 | 414 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 484 } | 489 } |
| 485 | 490 |
| 486 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { | 491 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { |
| 487 DCHECK(!v4l2_thread_.IsRunning() || | 492 DCHECK(!v4l2_thread_.IsRunning() || |
| 488 v4l2_thread_.message_loop() == base::MessageLoop::current()); | 493 v4l2_thread_.message_loop() == base::MessageLoop::current()); |
| 489 is_capturing_ = false; | 494 is_capturing_ = false; |
| 490 client_->OnError(reason); | 495 client_->OnError(reason); |
| 491 } | 496 } |
| 492 | 497 |
| 493 } // namespace media | 498 } // namespace media |
| OLD | NEW |