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 |