• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "media/video/capture/linux/video_capture_device_linux.h"
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #if defined(OS_OPENBSD)
10 #include <sys/videoio.h>
11 #else
12 #include <linux/videodev2.h>
13 #endif
14 #include <sys/ioctl.h>
15 #include <sys/mman.h>
16 
17 #include <list>
18 #include <string>
19 
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"
25 
26 namespace media {
27 
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 prefered 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 };
42 
43 // V4L2 color formats VideoCaptureDeviceLinux support.
44 static const int32 kV4l2RawFmts[] = {
45   V4L2_PIX_FMT_YUV420,
46   V4L2_PIX_FMT_YUYV
47 };
48 
49 // USB VID and PID are both 4 bytes long.
50 static const size_t kVidPidSize = 4;
51 
52 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding
53 // USB device info directory.
54 static const char kVidPathTemplate[] =
55     "/sys/class/video4linux/%s/device/../idVendor";
56 static const char kPidPathTemplate[] =
57     "/sys/class/video4linux/%s/device/../idProduct";
58 
ReadIdFile(const std::string path,std::string * id)59 bool ReadIdFile(const std::string path, std::string* id) {
60   char id_buf[kVidPidSize];
61   FILE* file = fopen(path.c_str(), "rb");
62   if (!file)
63     return false;
64   const bool success = fread(id_buf, kVidPidSize, 1, file) == 1;
65   fclose(file);
66   if (!success)
67     return false;
68   id->append(id_buf, kVidPidSize);
69   return true;
70 }
71 
72 // This function translates Video4Linux pixel formats to Chromium pixel formats,
73 // should only support those listed in GetListOfUsableFourCCs.
74 // static
V4l2ColorToVideoCaptureColorFormat(int32 v4l2_fourcc)75 VideoPixelFormat VideoCaptureDeviceLinux::V4l2ColorToVideoCaptureColorFormat(
76     int32 v4l2_fourcc) {
77   VideoPixelFormat result = PIXEL_FORMAT_UNKNOWN;
78   switch (v4l2_fourcc) {
79     case V4L2_PIX_FMT_YUV420:
80       result = PIXEL_FORMAT_I420;
81       break;
82     case V4L2_PIX_FMT_YUYV:
83       result = PIXEL_FORMAT_YUY2;
84       break;
85     case V4L2_PIX_FMT_MJPEG:
86     case V4L2_PIX_FMT_JPEG:
87       result = PIXEL_FORMAT_MJPEG;
88       break;
89     default:
90       DVLOG(1) << "Unsupported pixel format " << std::hex << v4l2_fourcc;
91   }
92   return result;
93 }
94 
95 // static
GetListOfUsableFourCCs(bool favour_mjpeg,std::list<int> * fourccs)96 void VideoCaptureDeviceLinux::GetListOfUsableFourCCs(bool favour_mjpeg,
97                                                      std::list<int>* fourccs) {
98   for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i)
99     fourccs->push_back(kV4l2RawFmts[i]);
100   if (favour_mjpeg)
101     fourccs->push_front(V4L2_PIX_FMT_MJPEG);
102   else
103     fourccs->push_back(V4L2_PIX_FMT_MJPEG);
104 
105   // JPEG works as MJPEG on some gspca webcams from field reports.
106   // Put it as the least preferred format.
107   fourccs->push_back(V4L2_PIX_FMT_JPEG);
108 }
109 
GetModel() const110 const std::string VideoCaptureDevice::Name::GetModel() const {
111   // |unique_id| is of the form "/dev/video2".  |file_name| is "video2".
112   const std::string dev_dir = "/dev/";
113   DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir));
114   const std::string file_name =
115       unique_id_.substr(dev_dir.length(), unique_id_.length());
116 
117   const std::string vidPath =
118       base::StringPrintf(kVidPathTemplate, file_name.c_str());
119   const std::string pidPath =
120       base::StringPrintf(kPidPathTemplate, file_name.c_str());
121 
122   std::string usb_id;
123   if (!ReadIdFile(vidPath, &usb_id))
124     return "";
125   usb_id.append(":");
126   if (!ReadIdFile(pidPath, &usb_id))
127     return "";
128 
129   return usb_id;
130 }
131 
VideoCaptureDeviceLinux(const Name & device_name)132 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name)
133     : state_(kIdle),
134       device_name_(device_name),
135       v4l2_thread_("V4L2Thread"),
136       buffer_pool_(NULL),
137       buffer_pool_size_(0),
138       timeout_count_(0),
139       rotation_(0) {
140 }
141 
~VideoCaptureDeviceLinux()142 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() {
143   state_ = kIdle;
144   // Check if the thread is running.
145   // This means that the device have not been DeAllocated properly.
146   DCHECK(!v4l2_thread_.IsRunning());
147   v4l2_thread_.Stop();
148 }
149 
AllocateAndStart(const VideoCaptureParams & params,scoped_ptr<VideoCaptureDevice::Client> client)150 void VideoCaptureDeviceLinux::AllocateAndStart(
151     const VideoCaptureParams& params,
152     scoped_ptr<VideoCaptureDevice::Client> client) {
153   if (v4l2_thread_.IsRunning()) {
154     return;  // Wrong state.
155   }
156   v4l2_thread_.Start();
157   v4l2_thread_.message_loop()->PostTask(
158       FROM_HERE,
159       base::Bind(&VideoCaptureDeviceLinux::OnAllocateAndStart,
160                  base::Unretained(this),
161                  params.requested_format.frame_size.width(),
162                  params.requested_format.frame_size.height(),
163                  params.requested_format.frame_rate,
164                  base::Passed(&client)));
165 }
166 
StopAndDeAllocate()167 void VideoCaptureDeviceLinux::StopAndDeAllocate() {
168   if (!v4l2_thread_.IsRunning()) {
169     return;  // Wrong state.
170   }
171   v4l2_thread_.message_loop()->PostTask(
172       FROM_HERE,
173       base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate,
174                  base::Unretained(this)));
175   v4l2_thread_.Stop();
176   // Make sure no buffers are still allocated.
177   // This can happen (theoretically) if an error occurs when trying to stop
178   // the camera.
179   DeAllocateVideoBuffers();
180 }
181 
SetRotation(int rotation)182 void VideoCaptureDeviceLinux::SetRotation(int rotation) {
183   if (v4l2_thread_.IsRunning()) {
184     v4l2_thread_.message_loop()->PostTask(
185         FROM_HERE,
186         base::Bind(&VideoCaptureDeviceLinux::SetRotationOnV4L2Thread,
187                    base::Unretained(this), rotation));
188   } else {
189     // If the |v4l2_thread_| is not running, there's no race condition and
190     // |rotation_| can be set directly.
191     rotation_ = rotation;
192   }
193 }
194 
SetRotationOnV4L2Thread(int rotation)195 void VideoCaptureDeviceLinux::SetRotationOnV4L2Thread(int rotation) {
196   DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
197   DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
198   rotation_ = rotation;
199 }
200 
OnAllocateAndStart(int width,int height,int frame_rate,scoped_ptr<Client> client)201 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width,
202                                                  int height,
203                                                  int frame_rate,
204                                                  scoped_ptr<Client> client) {
205   DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
206 
207   client_ = client.Pass();
208 
209   // Need to open camera with O_RDWR after Linux kernel 3.3.
210   device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR)));
211   if (!device_fd_.is_valid()) {
212     SetErrorState("Failed to open V4L2 device driver.");
213     return;
214   }
215 
216   // Test if this is a V4L2 capture device.
217   v4l2_capability cap;
218   if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
219         (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) &&
220         !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) {
221     // This is not a V4L2 video capture device.
222     device_fd_.reset();
223     SetErrorState("This is not a V4L2 video capture device");
224     return;
225   }
226 
227   // Get supported video formats in preferred order.
228   // For large resolutions, favour mjpeg over raw formats.
229   std::list<int> v4l2_formats;
230   GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight,
231                          &v4l2_formats);
232 
233   v4l2_fmtdesc fmtdesc = {0};
234   fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
235 
236   // Enumerate image formats.
237   std::list<int>::iterator best = v4l2_formats.end();
238   while (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) ==
239          0) {
240     best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat);
241     fmtdesc.index++;
242   }
243 
244   if (best == v4l2_formats.end()) {
245     SetErrorState("Failed to find a supported camera format.");
246     return;
247   }
248 
249   // Set format and frame size now.
250   v4l2_format video_fmt;
251   memset(&video_fmt, 0, sizeof(v4l2_format));
252   video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
253   video_fmt.fmt.pix.sizeimage = 0;
254   video_fmt.fmt.pix.width = width;
255   video_fmt.fmt.pix.height = height;
256   video_fmt.fmt.pix.pixelformat = *best;
257 
258   if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt)) < 0) {
259     SetErrorState("Failed to set camera format");
260     return;
261   }
262 
263   // Set capture framerate in the form of capture interval.
264   v4l2_streamparm streamparm;
265   memset(&streamparm, 0, sizeof(v4l2_streamparm));
266   streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
267   // The following line checks that the driver knows about framerate get/set.
268   if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) {
269     // Now check if the device is able to accept a capture framerate set.
270     if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
271       // |frame_rate| is float, approximate by a fraction.
272       streamparm.parm.capture.timeperframe.numerator =
273           media::kFrameRatePrecision;
274       streamparm.parm.capture.timeperframe.denominator = (frame_rate) ?
275           (frame_rate * media::kFrameRatePrecision) :
276           (kTypicalFramerate * media::kFrameRatePrecision);
277 
278       if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) <
279           0) {
280         SetErrorState("Failed to set camera framerate");
281         return;
282       }
283       DVLOG(2) << "Actual camera driverframerate: "
284                << streamparm.parm.capture.timeperframe.denominator << "/"
285                << streamparm.parm.capture.timeperframe.numerator;
286     }
287   }
288   // TODO(mcasas): what should be done if the camera driver does not allow
289   // framerate configuration, or the actual one is different from the desired?
290 
291   // Set anti-banding/anti-flicker to 50/60Hz. May fail due to not supported
292   // operation (|errno| == EINVAL in this case) or plain failure.
293   const int power_line_frequency = GetPowerLineFrequencyForLocation();
294   if ((power_line_frequency == kPowerLine50Hz) ||
295       (power_line_frequency == kPowerLine60Hz)) {
296     struct v4l2_control control = {};
297     control.id = V4L2_CID_POWER_LINE_FREQUENCY;
298     control.value = (power_line_frequency == kPowerLine50Hz) ?
299                         V4L2_CID_POWER_LINE_FREQUENCY_50HZ :
300                         V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
301     HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control));
302   }
303 
304   // Store our current width and height.
305   capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width,
306                                      video_fmt.fmt.pix.height);
307   capture_format_.frame_rate = frame_rate;
308   capture_format_.pixel_format =
309       V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat);
310 
311   // Start capturing.
312   if (!AllocateVideoBuffers()) {
313     // Error, We can not recover.
314     SetErrorState("Allocate buffer failed");
315     return;
316   }
317 
318   // Start UVC camera.
319   v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
320   if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) == -1) {
321     SetErrorState("VIDIOC_STREAMON failed");
322     return;
323   }
324 
325   state_ = kCapturing;
326   // Post task to start fetching frames from v4l2.
327   v4l2_thread_.message_loop()->PostTask(
328       FROM_HERE,
329       base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
330                  base::Unretained(this)));
331 }
332 
OnStopAndDeAllocate()333 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() {
334   DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
335 
336   v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
337   if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) {
338     SetErrorState("VIDIOC_STREAMOFF failed");
339     return;
340   }
341   // We don't dare to deallocate the buffers if we can't stop
342   // the capture device.
343   DeAllocateVideoBuffers();
344 
345   // We need to close and open the device if we want to change the settings
346   // Otherwise VIDIOC_S_FMT will return error
347   // Sad but true.
348   device_fd_.reset();
349   state_ = kIdle;
350   client_.reset();
351 }
352 
OnCaptureTask()353 void VideoCaptureDeviceLinux::OnCaptureTask() {
354   DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
355 
356   if (state_ != kCapturing) {
357     return;
358   }
359 
360   fd_set r_set;
361   FD_ZERO(&r_set);
362   FD_SET(device_fd_.get(), &r_set);
363   timeval timeout;
364 
365   timeout.tv_sec = 0;
366   timeout.tv_usec = kCaptureTimeoutUs;
367 
368   // First argument to select is the highest numbered file descriptor +1.
369   // Refer to http://linux.die.net/man/2/select for more information.
370   int result =
371       HANDLE_EINTR(select(device_fd_.get() + 1, &r_set, NULL, NULL, &timeout));
372   // Check if select have failed.
373   if (result < 0) {
374     // EINTR is a signal. This is not really an error.
375     if (errno != EINTR) {
376       SetErrorState("Select failed");
377       return;
378     }
379     v4l2_thread_.message_loop()->PostDelayedTask(
380         FROM_HERE,
381         base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
382                    base::Unretained(this)),
383         base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs));
384   }
385 
386   // Check if select timeout.
387   if (result == 0) {
388     timeout_count_++;
389     if (timeout_count_ >= kContinuousTimeoutLimit) {
390       SetErrorState(base::StringPrintf(
391           "Continuous timeout %d times", timeout_count_));
392       timeout_count_ = 0;
393       return;
394     }
395   } else {
396     timeout_count_ = 0;
397   }
398 
399   // Check if the driver have filled a buffer.
400   if (FD_ISSET(device_fd_.get(), &r_set)) {
401     v4l2_buffer buffer;
402     memset(&buffer, 0, sizeof(buffer));
403     buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
404     buffer.memory = V4L2_MEMORY_MMAP;
405     // Dequeue a buffer.
406     if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) {
407       client_->OnIncomingCapturedData(
408           static_cast<uint8*>(buffer_pool_[buffer.index].start),
409           buffer.bytesused,
410           capture_format_,
411           rotation_,
412           base::TimeTicks::Now());
413 
414       // Enqueue the buffer again.
415       if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) {
416         SetErrorState(base::StringPrintf(
417             "Failed to enqueue capture buffer errno %d", errno));
418       }
419     } else {
420       SetErrorState(base::StringPrintf(
421           "Failed to dequeue capture buffer errno %d", errno));
422       return;
423     }
424   }
425 
426   v4l2_thread_.message_loop()->PostTask(
427       FROM_HERE,
428       base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
429                  base::Unretained(this)));
430 }
431 
AllocateVideoBuffers()432 bool VideoCaptureDeviceLinux::AllocateVideoBuffers() {
433   v4l2_requestbuffers r_buffer;
434   memset(&r_buffer, 0, sizeof(r_buffer));
435 
436   r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
437   r_buffer.memory = V4L2_MEMORY_MMAP;
438   r_buffer.count = kMaxVideoBuffers;
439 
440   if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
441     return false;
442   }
443 
444   if (r_buffer.count > kMaxVideoBuffers) {
445     r_buffer.count = kMaxVideoBuffers;
446   }
447 
448   buffer_pool_size_ = r_buffer.count;
449 
450   // Map the buffers.
451   buffer_pool_ = new Buffer[r_buffer.count];
452   for (unsigned int i = 0; i < r_buffer.count; i++) {
453     v4l2_buffer buffer;
454     memset(&buffer, 0, sizeof(buffer));
455     buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
456     buffer.memory = V4L2_MEMORY_MMAP;
457     buffer.index = i;
458 
459     if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
460       return false;
461     }
462 
463     // Some devices require mmap() to be called with both READ and WRITE.
464     // See crbug.com/178582.
465     buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
466                                  MAP_SHARED, device_fd_.get(), buffer.m.offset);
467     if (buffer_pool_[i].start == MAP_FAILED) {
468       return false;
469     }
470     buffer_pool_[i].length = buffer.length;
471     // Enqueue the buffer in the drivers incoming queue.
472     if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
473       return false;
474     }
475   }
476   return true;
477 }
478 
DeAllocateVideoBuffers()479 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() {
480   if (!buffer_pool_)
481     return;
482 
483   // Unmaps buffers.
484   for (int i = 0; i < buffer_pool_size_; i++) {
485     munmap(buffer_pool_[i].start, buffer_pool_[i].length);
486   }
487   v4l2_requestbuffers r_buffer;
488   memset(&r_buffer, 0, sizeof(r_buffer));
489   r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
490   r_buffer.memory = V4L2_MEMORY_MMAP;
491   r_buffer.count = 0;
492 
493   if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
494     SetErrorState("Failed to reset buf.");
495   }
496 
497   delete [] buffer_pool_;
498   buffer_pool_ = NULL;
499   buffer_pool_size_ = 0;
500 }
501 
SetErrorState(const std::string & reason)502 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) {
503   DCHECK(!v4l2_thread_.IsRunning() ||
504          v4l2_thread_.message_loop() == base::MessageLoop::current());
505   DVLOG(1) << reason;
506   state_ = kError;
507   client_->OnError(reason);
508 }
509 
510 }  // namespace media
511