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
3 // found in the LICENSE file.
5 #include "media/video/capture/linux/video_capture_device_linux.h"
9 #if defined(OS_OPENBSD)
10 #include <sys/videoio.h>
12 #include <linux/videodev2.h>
14 #include <sys/ioctl.h>
20 #include "base/bind.h"
21 #include "base/files/file_enumerator.h"
22 #include "base/files/scoped_file.h"
23 #include "base/posix/eintr_wrapper.h"
24 #include "base/strings/stringprintf.h"
28 // Max number of video buffers VideoCaptureDeviceLinux can allocate.
29 enum { kMaxVideoBuffers = 2 };
30 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw.
31 enum { kCaptureTimeoutUs = 200000 };
32 // The number of continuous timeouts tolerated before treated as error.
33 enum { kContinuousTimeoutLimit = 10 };
34 // Time to wait in milliseconds before v4l2_thread_ reschedules OnCaptureTask
35 // if an event is triggered (select) but no video frame is read.
36 enum { kCaptureSelectWaitMs = 10 };
37 // MJPEG is preferred if the width or height is larger than this.
38 enum { kMjpegWidth = 640 };
39 enum { kMjpegHeight = 480 };
40 // Typical framerate, in fps
41 enum { kTypicalFramerate = 30 };
43 // V4L2 color formats VideoCaptureDeviceLinux support.
44 static const int32 kV4l2RawFmts[] = {
50 // USB VID and PID are both 4 bytes long.
51 static const size_t kVidPidSize = 4;
53 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding
54 // USB device info directory.
55 static const char kVidPathTemplate[] =
56 "/sys/class/video4linux/%s/device/../idVendor";
57 static const char kPidPathTemplate[] =
58 "/sys/class/video4linux/%s/device/../idProduct";
60 bool ReadIdFile(const std::string path, std::string* id) {
61 char id_buf[kVidPidSize];
62 FILE* file = fopen(path.c_str(), "rb");
65 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1;
69 id->append(id_buf, kVidPidSize);
73 // This function translates Video4Linux pixel formats to Chromium pixel formats,
74 // should only support those listed in GetListOfUsableFourCCs.
76 VideoPixelFormat VideoCaptureDeviceLinux::V4l2ColorToVideoCaptureColorFormat(
78 VideoPixelFormat result = PIXEL_FORMAT_UNKNOWN;
79 switch (v4l2_fourcc) {
80 case V4L2_PIX_FMT_YUV420:
81 result = PIXEL_FORMAT_I420;
83 case V4L2_PIX_FMT_YUYV:
84 result = PIXEL_FORMAT_YUY2;
86 case V4L2_PIX_FMT_UYVY:
87 result = PIXEL_FORMAT_UYVY;
89 case V4L2_PIX_FMT_MJPEG:
90 case V4L2_PIX_FMT_JPEG:
91 result = PIXEL_FORMAT_MJPEG;
94 DVLOG(1) << "Unsupported pixel format " << std::hex << v4l2_fourcc;
100 void VideoCaptureDeviceLinux::GetListOfUsableFourCCs(bool favour_mjpeg,
101 std::list<int>* fourccs) {
102 for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i)
103 fourccs->push_back(kV4l2RawFmts[i]);
105 fourccs->push_front(V4L2_PIX_FMT_MJPEG);
107 fourccs->push_back(V4L2_PIX_FMT_MJPEG);
109 // JPEG works as MJPEG on some gspca webcams from field reports.
110 // Put it as the least preferred format.
111 fourccs->push_back(V4L2_PIX_FMT_JPEG);
114 const std::string VideoCaptureDevice::Name::GetModel() const {
115 // |unique_id| is of the form "/dev/video2". |file_name| is "video2".
116 const std::string dev_dir = "/dev/";
117 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir));
118 const std::string file_name =
119 unique_id_.substr(dev_dir.length(), unique_id_.length());
121 const std::string vidPath =
122 base::StringPrintf(kVidPathTemplate, file_name.c_str());
123 const std::string pidPath =
124 base::StringPrintf(kPidPathTemplate, file_name.c_str());
127 if (!ReadIdFile(vidPath, &usb_id))
130 if (!ReadIdFile(pidPath, &usb_id))
136 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name)
137 : is_capturing_(false),
138 device_name_(device_name),
139 v4l2_thread_("V4L2Thread"),
141 buffer_pool_size_(0),
146 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() {
147 // Check if the thread is running.
148 // This means that the device have not been DeAllocated properly.
149 DCHECK(!v4l2_thread_.IsRunning());
153 void VideoCaptureDeviceLinux::AllocateAndStart(
154 const VideoCaptureParams& params,
155 scoped_ptr<VideoCaptureDevice::Client> client) {
156 if (v4l2_thread_.IsRunning()) {
157 return; // Wrong state.
159 v4l2_thread_.Start();
160 v4l2_thread_.message_loop()->PostTask(
162 base::Bind(&VideoCaptureDeviceLinux::OnAllocateAndStart,
163 base::Unretained(this),
164 params.requested_format.frame_size.width(),
165 params.requested_format.frame_size.height(),
166 params.requested_format.frame_rate,
167 base::Passed(&client)));
170 void VideoCaptureDeviceLinux::StopAndDeAllocate() {
171 if (!v4l2_thread_.IsRunning()) {
172 return; // Wrong state.
174 v4l2_thread_.message_loop()->PostTask(
176 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate,
177 base::Unretained(this)));
179 // Make sure no buffers are still allocated.
180 // This can happen (theoretically) if an error occurs when trying to stop
182 DeAllocateVideoBuffers();
185 void VideoCaptureDeviceLinux::SetRotation(int rotation) {
186 if (v4l2_thread_.IsRunning()) {
187 v4l2_thread_.message_loop()->PostTask(
189 base::Bind(&VideoCaptureDeviceLinux::SetRotationOnV4L2Thread,
190 base::Unretained(this), rotation));
192 // If the |v4l2_thread_| is not running, there's no race condition and
193 // |rotation_| can be set directly.
194 rotation_ = rotation;
198 void VideoCaptureDeviceLinux::SetRotationOnV4L2Thread(int rotation) {
199 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
200 DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
201 rotation_ = rotation;
204 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width,
207 scoped_ptr<Client> client) {
208 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
210 client_ = client.Pass();
212 // Need to open camera with O_RDWR after Linux kernel 3.3.
213 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR)));
214 if (!device_fd_.is_valid()) {
215 SetErrorState("Failed to open V4L2 device driver.");
219 // Test if this is a V4L2 capture device.
221 if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
222 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) &&
223 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) {
224 // This is not a V4L2 video capture device.
226 SetErrorState("This is not a V4L2 video capture device");
230 // Get supported video formats in preferred order.
231 // For large resolutions, favour mjpeg over raw formats.
232 std::list<int> v4l2_formats;
233 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight,
236 v4l2_fmtdesc fmtdesc = {0};
237 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
239 // Enumerate image formats.
240 std::list<int>::iterator best = v4l2_formats.end();
241 while (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) ==
243 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat);
247 if (best == v4l2_formats.end()) {
248 SetErrorState("Failed to find a supported camera format.");
252 // Set format and frame size now.
253 v4l2_format video_fmt;
254 memset(&video_fmt, 0, sizeof(v4l2_format));
255 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
256 video_fmt.fmt.pix.sizeimage = 0;
257 video_fmt.fmt.pix.width = width;
258 video_fmt.fmt.pix.height = height;
259 video_fmt.fmt.pix.pixelformat = *best;
261 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt)) < 0) {
263 base::StringPrintf("Failed to set camera format: %s", strerror(errno)));
267 // Set capture framerate in the form of capture interval.
268 v4l2_streamparm streamparm;
269 memset(&streamparm, 0, sizeof(v4l2_streamparm));
270 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
271 // The following line checks that the driver knows about framerate get/set.
272 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) {
273 // Now check if the device is able to accept a capture framerate set.
274 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
275 // |frame_rate| is float, approximate by a fraction.
276 streamparm.parm.capture.timeperframe.numerator =
277 media::kFrameRatePrecision;
278 streamparm.parm.capture.timeperframe.denominator = (frame_rate) ?
279 (frame_rate * media::kFrameRatePrecision) :
280 (kTypicalFramerate * media::kFrameRatePrecision);
282 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) <
284 SetErrorState("Failed to set camera framerate");
287 DVLOG(2) << "Actual camera driverframerate: "
288 << streamparm.parm.capture.timeperframe.denominator << "/"
289 << streamparm.parm.capture.timeperframe.numerator;
292 // TODO(mcasas): what should be done if the camera driver does not allow
293 // framerate configuration, or the actual one is different from the desired?
295 // Set anti-banding/anti-flicker to 50/60Hz. May fail due to not supported
296 // operation (|errno| == EINVAL in this case) or plain failure.
297 const int power_line_frequency = GetPowerLineFrequencyForLocation();
298 if ((power_line_frequency == kPowerLine50Hz) ||
299 (power_line_frequency == kPowerLine60Hz)) {
300 struct v4l2_control control = {};
301 control.id = V4L2_CID_POWER_LINE_FREQUENCY;
302 control.value = (power_line_frequency == kPowerLine50Hz) ?
303 V4L2_CID_POWER_LINE_FREQUENCY_50HZ :
304 V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
305 HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control));
308 // Store our current width and height.
309 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width,
310 video_fmt.fmt.pix.height);
311 capture_format_.frame_rate = frame_rate;
312 capture_format_.pixel_format =
313 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat);
316 if (!AllocateVideoBuffers()) {
317 // Error, We can not recover.
318 SetErrorState("Allocate buffer failed");
323 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
324 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) == -1) {
325 SetErrorState("VIDIOC_STREAMON failed");
329 is_capturing_ = true;
330 // Post task to start fetching frames from v4l2.
331 v4l2_thread_.message_loop()->PostTask(
333 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
334 base::Unretained(this)));
337 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() {
338 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
340 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
341 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) {
342 SetErrorState("VIDIOC_STREAMOFF failed");
345 // We don't dare to deallocate the buffers if we can't stop
346 // the capture device.
347 DeAllocateVideoBuffers();
349 // We need to close and open the device if we want to change the settings
350 // Otherwise VIDIOC_S_FMT will return error
353 is_capturing_ = false;
357 void VideoCaptureDeviceLinux::OnCaptureTask() {
358 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
364 FD_SET(device_fd_.get(), &r_set);
368 timeout.tv_usec = kCaptureTimeoutUs;
370 // First argument to select is the highest numbered file descriptor +1.
371 // Refer to http://linux.die.net/man/2/select for more information.
373 HANDLE_EINTR(select(device_fd_.get() + 1, &r_set, NULL, NULL, &timeout));
374 // Check if select have failed.
376 // EINTR is a signal. This is not really an error.
377 if (errno != EINTR) {
378 SetErrorState("Select failed");
381 v4l2_thread_.message_loop()->PostDelayedTask(
383 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
384 base::Unretained(this)),
385 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs));
388 // Check if select timeout.
391 if (timeout_count_ >= kContinuousTimeoutLimit) {
392 SetErrorState(base::StringPrintf(
393 "Continuous timeout %d times", timeout_count_));
401 // Check if the driver have filled a buffer.
402 if (FD_ISSET(device_fd_.get(), &r_set)) {
404 memset(&buffer, 0, sizeof(buffer));
405 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
406 buffer.memory = V4L2_MEMORY_MMAP;
408 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) {
409 client_->OnIncomingCapturedData(
410 static_cast<uint8*>(buffer_pool_[buffer.index].start),
414 base::TimeTicks::Now());
416 // Enqueue the buffer again.
417 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) {
418 SetErrorState(base::StringPrintf(
419 "Failed to enqueue capture buffer errno %d", errno));
422 SetErrorState(base::StringPrintf(
423 "Failed to dequeue capture buffer errno %d", errno));
428 v4l2_thread_.message_loop()->PostTask(
430 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
431 base::Unretained(this)));
434 bool VideoCaptureDeviceLinux::AllocateVideoBuffers() {
435 v4l2_requestbuffers r_buffer;
436 memset(&r_buffer, 0, sizeof(r_buffer));
438 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
439 r_buffer.memory = V4L2_MEMORY_MMAP;
440 r_buffer.count = kMaxVideoBuffers;
442 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
446 if (r_buffer.count > kMaxVideoBuffers) {
447 r_buffer.count = kMaxVideoBuffers;
450 buffer_pool_size_ = r_buffer.count;
453 buffer_pool_ = new Buffer[r_buffer.count];
454 for (unsigned int i = 0; i < r_buffer.count; i++) {
456 memset(&buffer, 0, sizeof(buffer));
457 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
458 buffer.memory = V4L2_MEMORY_MMAP;
461 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
465 // Some devices require mmap() to be called with both READ and WRITE.
466 // See crbug.com/178582.
467 buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
468 MAP_SHARED, device_fd_.get(), buffer.m.offset);
469 if (buffer_pool_[i].start == MAP_FAILED) {
472 buffer_pool_[i].length = buffer.length;
473 // Enqueue the buffer in the drivers incoming queue.
474 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
481 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() {
486 for (int i = 0; i < buffer_pool_size_; i++) {
487 munmap(buffer_pool_[i].start, buffer_pool_[i].length);
489 v4l2_requestbuffers r_buffer;
490 memset(&r_buffer, 0, sizeof(r_buffer));
491 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
492 r_buffer.memory = V4L2_MEMORY_MMAP;
495 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
496 SetErrorState("Failed to reset buf.");
499 delete [] buffer_pool_;
501 buffer_pool_size_ = 0;
504 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) {
505 DCHECK(!v4l2_thread_.IsRunning() ||
506 v4l2_thread_.message_loop() == base::MessageLoop::current());
507 is_capturing_ = false;
508 client_->OnError(reason);