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 |