| 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> |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 152 return; | 152 return; |
| 153 int fd; | 153 int fd; |
| 154 VideoCaptureCapabilities capture_formats; | 154 VideoCaptureCapabilities capture_formats; |
| 155 if ((fd = open(device.id().c_str(), O_RDONLY)) < 0) { | 155 if ((fd = open(device.id().c_str(), O_RDONLY)) < 0) { |
| 156 // Failed to open this device. | 156 // Failed to open this device. |
| 157 return; | 157 return; |
| 158 } | 158 } |
| 159 | 159 |
| 160 formats->clear(); | 160 formats->clear(); |
| 161 | 161 |
| 162 VideoCaptureCapability capture_format; | 162 VideoCaptureCapability capture_capability; |
| 163 // Retrieve the caps one by one, first get colorspace, then sizes, then | 163 // Retrieve the caps one by one, first get colorspace, then sizes, then |
| 164 // framerates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. | 164 // framerates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. |
| 165 v4l2_fmtdesc pixel_format = {}; | 165 v4l2_fmtdesc pixel_format = {}; |
| 166 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 166 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 167 while (ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format) == 0) { | 167 while (ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format) == 0) { |
| 168 capture_format.color = | 168 capture_capability.supported_format.pixel_format = |
| 169 V4l2ColorToVideoCaptureColorFormat((int32)pixel_format.pixelformat); | 169 V4l2ColorToVideoCaptureColorFormat((int32)pixel_format.pixelformat); |
| 170 if (capture_format.color == PIXEL_FORMAT_UNKNOWN) continue; | 170 if (capture_capability.supported_format.pixel_format == |
| 171 PIXEL_FORMAT_UNKNOWN) { |
| 172 continue; |
| 173 } |
| 171 | 174 |
| 172 v4l2_frmsizeenum frame_size = {}; | 175 v4l2_frmsizeenum frame_size = {}; |
| 173 frame_size.pixel_format = pixel_format.pixelformat; | 176 frame_size.pixel_format = pixel_format.pixelformat; |
| 174 while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0) { | 177 while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0) { |
| 175 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { | 178 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { |
| 176 capture_format.width = frame_size.discrete.width; | 179 capture_capability.supported_format.frame_size.SetSize( |
| 177 capture_format.height = frame_size.discrete.height; | 180 frame_size.discrete.width, frame_size.discrete.height); |
| 178 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { | 181 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { |
| 179 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 182 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
| 180 NOTIMPLEMENTED(); | 183 NOTIMPLEMENTED(); |
| 181 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { | 184 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { |
| 182 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 185 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
| 183 NOTIMPLEMENTED(); | 186 NOTIMPLEMENTED(); |
| 184 } | 187 } |
| 185 v4l2_frmivalenum frame_interval = {}; | 188 v4l2_frmivalenum frame_interval = {}; |
| 186 frame_interval.pixel_format = pixel_format.pixelformat; | 189 frame_interval.pixel_format = pixel_format.pixelformat; |
| 187 frame_interval.width = frame_size.discrete.width; | 190 frame_interval.width = frame_size.discrete.width; |
| 188 frame_interval.height = frame_size.discrete.height; | 191 frame_interval.height = frame_size.discrete.height; |
| 189 while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval) == 0) { | 192 while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval) == 0) { |
| 190 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { | 193 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { |
| 191 if (frame_interval.discrete.numerator != 0) { | 194 if (frame_interval.discrete.numerator != 0) { |
| 192 capture_format.frame_rate = | 195 capture_capability.supported_format.frame_rate = |
| 193 static_cast<float>(frame_interval.discrete.denominator) / | 196 static_cast<float>(frame_interval.discrete.denominator) / |
| 194 static_cast<float>(frame_interval.discrete.numerator); | 197 static_cast<float>(frame_interval.discrete.numerator); |
| 195 } else { | 198 } else { |
| 196 capture_format.frame_rate = 0; | 199 capture_capability.supported_format.frame_rate = 0; |
| 197 } | 200 } |
| 198 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { | 201 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { |
| 199 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 202 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
| 200 NOTIMPLEMENTED(); | 203 NOTIMPLEMENTED(); |
| 201 break; | 204 break; |
| 202 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { | 205 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { |
| 203 // TODO(mcasas): see http://crbug.com/249953, support these devices. | 206 // TODO(mcasas): see http://crbug.com/249953, support these devices. |
| 204 NOTIMPLEMENTED(); | 207 NOTIMPLEMENTED(); |
| 205 break; | 208 break; |
| 206 } | 209 } |
| 207 formats->push_back(capture_format); | 210 formats->push_back(capture_capability); |
| 208 ++frame_interval.index; | 211 ++frame_interval.index; |
| 209 } | 212 } |
| 210 ++frame_size.index; | 213 ++frame_size.index; |
| 211 } | 214 } |
| 212 ++pixel_format.index; | 215 ++pixel_format.index; |
| 213 } | 216 } |
| 214 | 217 |
| 215 close(fd); | 218 close(fd); |
| 216 return; | 219 return; |
| 217 } | 220 } |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 // This means that the device have not been DeAllocated properly. | 287 // This means that the device have not been DeAllocated properly. |
| 285 DCHECK(!v4l2_thread_.IsRunning()); | 288 DCHECK(!v4l2_thread_.IsRunning()); |
| 286 | 289 |
| 287 v4l2_thread_.Stop(); | 290 v4l2_thread_.Stop(); |
| 288 if (device_fd_ >= 0) { | 291 if (device_fd_ >= 0) { |
| 289 close(device_fd_); | 292 close(device_fd_); |
| 290 } | 293 } |
| 291 } | 294 } |
| 292 | 295 |
| 293 void VideoCaptureDeviceLinux::AllocateAndStart( | 296 void VideoCaptureDeviceLinux::AllocateAndStart( |
| 294 const VideoCaptureCapability& capture_format, | 297 const VideoCaptureParams& params, |
| 295 scoped_ptr<VideoCaptureDevice::Client> client) { | 298 scoped_ptr<VideoCaptureDevice::Client> client) { |
| 296 if (v4l2_thread_.IsRunning()) { | 299 if (v4l2_thread_.IsRunning()) { |
| 297 return; // Wrong state. | 300 return; // Wrong state. |
| 298 } | 301 } |
| 299 v4l2_thread_.Start(); | 302 v4l2_thread_.Start(); |
| 300 v4l2_thread_.message_loop()->PostTask( | 303 v4l2_thread_.message_loop()->PostTask( |
| 301 FROM_HERE, | 304 FROM_HERE, |
| 302 base::Bind(&VideoCaptureDeviceLinux::OnAllocateAndStart, | 305 base::Bind(&VideoCaptureDeviceLinux::OnAllocateAndStart, |
| 303 base::Unretained(this), | 306 base::Unretained(this), |
| 304 capture_format.width, | 307 params.requested_format.frame_size.width(), |
| 305 capture_format.height, | 308 params.requested_format.frame_size.height(), |
| 306 capture_format.frame_rate, | 309 params.requested_format.frame_rate, |
| 307 base::Passed(&client))); | 310 base::Passed(&client))); |
| 308 } | 311 } |
| 309 | 312 |
| 310 void VideoCaptureDeviceLinux::StopAndDeAllocate() { | 313 void VideoCaptureDeviceLinux::StopAndDeAllocate() { |
| 311 if (!v4l2_thread_.IsRunning()) { | 314 if (!v4l2_thread_.IsRunning()) { |
| 312 return; // Wrong state. | 315 return; // Wrong state. |
| 313 } | 316 } |
| 314 v4l2_thread_.message_loop()->PostTask( | 317 v4l2_thread_.message_loop()->PostTask( |
| 315 FROM_HERE, | 318 FROM_HERE, |
| 316 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate, | 319 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate, |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 } | 405 } |
| 403 DVLOG(2) << "Actual camera driverframerate: " | 406 DVLOG(2) << "Actual camera driverframerate: " |
| 404 << streamparm.parm.capture.timeperframe.denominator << "/" | 407 << streamparm.parm.capture.timeperframe.denominator << "/" |
| 405 << streamparm.parm.capture.timeperframe.numerator; | 408 << streamparm.parm.capture.timeperframe.numerator; |
| 406 } | 409 } |
| 407 } | 410 } |
| 408 // TODO(mcasas): what should be done if the camera driver does not allow | 411 // TODO(mcasas): what should be done if the camera driver does not allow |
| 409 // framerate configuration, or the actual one is different from the desired? | 412 // framerate configuration, or the actual one is different from the desired? |
| 410 | 413 |
| 411 // Store our current width and height. | 414 // Store our current width and height. |
| 412 frame_info_.color = | 415 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width, |
| 416 video_fmt.fmt.pix.height); |
| 417 capture_format_.frame_rate = frame_rate; |
| 418 capture_format_.pixel_format = |
| 413 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat); | 419 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat); |
| 414 frame_info_.width = video_fmt.fmt.pix.width; | |
| 415 frame_info_.height = video_fmt.fmt.pix.height; | |
| 416 frame_info_.frame_rate = frame_rate; | |
| 417 frame_info_.frame_size_type = VariableResolutionVideoCaptureDevice; | |
| 418 | 420 |
| 419 // Start capturing. | 421 // Start capturing. |
| 420 if (!AllocateVideoBuffers()) { | 422 if (!AllocateVideoBuffers()) { |
| 421 // Error, We can not recover. | 423 // Error, We can not recover. |
| 422 SetErrorState("Allocate buffer failed"); | 424 SetErrorState("Allocate buffer failed"); |
| 423 return; | 425 return; |
| 424 } | 426 } |
| 425 | 427 |
| 426 // Start UVC camera. | 428 // Start UVC camera. |
| 427 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 429 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 buffer.memory = V4L2_MEMORY_MMAP; | 514 buffer.memory = V4L2_MEMORY_MMAP; |
| 513 // Dequeue a buffer. | 515 // Dequeue a buffer. |
| 514 if (ioctl(device_fd_, VIDIOC_DQBUF, &buffer) == 0) { | 516 if (ioctl(device_fd_, VIDIOC_DQBUF, &buffer) == 0) { |
| 515 client_->OnIncomingCapturedFrame( | 517 client_->OnIncomingCapturedFrame( |
| 516 static_cast<uint8*>(buffer_pool_[buffer.index].start), | 518 static_cast<uint8*>(buffer_pool_[buffer.index].start), |
| 517 buffer.bytesused, | 519 buffer.bytesused, |
| 518 base::Time::Now(), | 520 base::Time::Now(), |
| 519 0, | 521 0, |
| 520 false, | 522 false, |
| 521 false, | 523 false, |
| 522 frame_info_); | 524 capture_format_); |
| 523 | 525 |
| 524 // Enqueue the buffer again. | 526 // Enqueue the buffer again. |
| 525 if (ioctl(device_fd_, VIDIOC_QBUF, &buffer) == -1) { | 527 if (ioctl(device_fd_, VIDIOC_QBUF, &buffer) == -1) { |
| 526 SetErrorState(base::StringPrintf( | 528 SetErrorState(base::StringPrintf( |
| 527 "Failed to enqueue capture buffer errno %d", errno)); | 529 "Failed to enqueue capture buffer errno %d", errno)); |
| 528 } | 530 } |
| 529 } else { | 531 } else { |
| 530 SetErrorState(base::StringPrintf( | 532 SetErrorState(base::StringPrintf( |
| 531 "Failed to dequeue capture buffer errno %d", errno)); | 533 "Failed to dequeue capture buffer errno %d", errno)); |
| 532 return; | 534 return; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 611 | 613 |
| 612 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { | 614 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { |
| 613 DCHECK(!v4l2_thread_.IsRunning() || | 615 DCHECK(!v4l2_thread_.IsRunning() || |
| 614 v4l2_thread_.message_loop() == base::MessageLoop::current()); | 616 v4l2_thread_.message_loop() == base::MessageLoop::current()); |
| 615 DVLOG(1) << reason; | 617 DVLOG(1) << reason; |
| 616 state_ = kError; | 618 state_ = kError; |
| 617 client_->OnError(); | 619 client_->OnError(); |
| 618 } | 620 } |
| 619 | 621 |
| 620 } // namespace media | 622 } // namespace media |
| OLD | NEW |