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