- add sources.
[platform/framework/web/crosswalk.git] / src / media / video / capture / linux / video_capture_device_linux.cc
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 #if defined(OS_TIZEN_MOBILE)
17 extern "C" {
18 #include <mfld_cam.h>
19 }  // extern "C"
20 #endif
21
22 #include <list>
23 #include <string>
24
25 #include "base/bind.h"
26 #include "base/file_util.h"
27 #include "base/files/file_enumerator.h"
28 #include "base/native_library.h"
29 #include "base/strings/stringprintf.h"
30
31 namespace {
32
33 base::NativeLibrary mfld_library = NULL;
34
35 void* mfld_functions = NULL;
36
37 typedef void (*mfld_wrapper_default_link_functions_init_t)(void* functions);
38
39 typedef void (*mfld_libmfld_cam_init_t)(void* functions);
40
41 typedef int (*mfld_cam_driver_init_t)(int fd, const char* sensor_id);
42
43 typedef int (*mfld_cam_set_capture_fmt_t)(int fd,
44                                           unsigned int width,
45                                           unsigned int height,
46                                           unsigned int fourcc);
47
48 typedef int (*mfld_cam_driver_set_mipi_interrupt_t)(int fd, int enable);
49
50 typedef int (*mfld_cam_driver_deinit_t)(int fd);
51
52 #define MFLD_DEFINE_SYM(name) mfld_##name##_t mfld_##name = NULL
53 MFLD_DEFINE_SYM(wrapper_default_link_functions_init);
54 MFLD_DEFINE_SYM(libmfld_cam_init);
55 MFLD_DEFINE_SYM(cam_driver_init);
56 MFLD_DEFINE_SYM(cam_set_capture_fmt);
57 MFLD_DEFINE_SYM(cam_driver_set_mipi_interrupt);
58 MFLD_DEFINE_SYM(cam_driver_deinit);
59
60 #define MFLD_BIND_SYM(name)                                                    \
61   do {                                                                         \
62     mfld_##name = reinterpret_cast<mfld_##name##_t>(                           \
63         base::GetFunctionPointerFromNativeLibrary(mfld_library, #name));       \
64     if (!mfld_##name) {                                                        \
65       DVLOG(1) << "Failed to bind symbol "#name;                               \
66       base::UnloadNativeLibrary(mfld_library);                                 \
67       mfld_library = NULL;                                                     \
68       return;                                                                  \
69     }                                                                          \
70   } while (0)
71
72 void mfld_driver_initialize(void* functions) {
73   static bool is_initialized = false;
74   std::string error;
75
76   if (is_initialized)
77     return;
78
79   is_initialized = true;
80   mfld_library = base::LoadNativeLibrary(
81       base::FilePath("libgstatomisphal-0.10.so.0"), &error);
82   if (!mfld_library) {
83     DVLOG(4) << "Failed to load mfld camera driver: " << error;
84     return;
85   }
86   MFLD_BIND_SYM(wrapper_default_link_functions_init);
87   MFLD_BIND_SYM(libmfld_cam_init);
88   MFLD_BIND_SYM(cam_driver_init);
89   MFLD_BIND_SYM(cam_set_capture_fmt);
90   MFLD_BIND_SYM(cam_driver_set_mipi_interrupt);
91   MFLD_BIND_SYM(cam_driver_deinit);
92   mfld_wrapper_default_link_functions_init(functions);
93   mfld_libmfld_cam_init(functions);
94 }
95
96 enum { kCameraSensorSecondary, kCameraSensorPrimary };
97
98 #if defined(OS_TIZEN_MOBILE)
99 GstV4l2MFLDAdvCI mfld_adv_ci;
100 #endif
101
102 }  // namespace
103
104 namespace media {
105
106 // Max number of video buffers VideoCaptureDeviceLinux can allocate.
107 enum { kMaxVideoBuffers = 2 };
108 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw.
109 enum { kCaptureTimeoutUs = 200000 };
110 // The number of continuous timeouts tolerated before treated as error.
111 enum { kContinuousTimeoutLimit = 10 };
112 // Time to wait in milliseconds before v4l2_thread_ reschedules OnCaptureTask
113 // if an event is triggered (select) but no video frame is read.
114 enum { kCaptureSelectWaitMs = 10 };
115 // MJPEG is prefered if the width or height is larger than this.
116 enum { kMjpegWidth = 640 };
117 enum { kMjpegHeight = 480 };
118 // Typical framerate, in fps
119 enum { kTypicalFramerate = 30 };
120
121 // V4L2 color formats VideoCaptureDeviceLinux support.
122 static const int32 kV4l2RawFmts[] = {
123   V4L2_PIX_FMT_YUV420,
124   V4L2_PIX_FMT_YUYV
125 };
126
127 // USB VID and PID are both 4 bytes long.
128 static const size_t kVidPidSize = 4;
129
130 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding
131 // USB device info directory.
132 static const char kVidPathTemplate[] =
133     "/sys/class/video4linux/%s/device/../idVendor";
134 static const char kPidPathTemplate[] =
135     "/sys/class/video4linux/%s/device/../idProduct";
136
137 // This function translates Video4Linux pixel formats to Chromium pixel formats,
138 // should only support those listed in GetListOfUsableFourCCs.
139 static VideoPixelFormat V4l2ColorToVideoCaptureColorFormat(
140     int32 v4l2_fourcc) {
141   VideoPixelFormat result = PIXEL_FORMAT_UNKNOWN;
142   switch (v4l2_fourcc) {
143     case V4L2_PIX_FMT_YUV420:
144       result = PIXEL_FORMAT_I420;
145       break;
146     case V4L2_PIX_FMT_YUYV:
147       result = PIXEL_FORMAT_YUY2;
148       break;
149     case V4L2_PIX_FMT_MJPEG:
150     case V4L2_PIX_FMT_JPEG:
151       result = PIXEL_FORMAT_MJPEG;
152       break;
153     default:
154       DVLOG(1) << "Unsupported pixel format " << std::hex << v4l2_fourcc;
155   }
156   return result;
157 }
158
159 static void GetListOfUsableFourCCs(bool favour_mjpeg, std::list<int>* fourccs) {
160   for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i)
161     fourccs->push_back(kV4l2RawFmts[i]);
162   if (favour_mjpeg)
163     fourccs->push_front(V4L2_PIX_FMT_MJPEG);
164   else
165     fourccs->push_back(V4L2_PIX_FMT_MJPEG);
166
167   // JPEG works as MJPEG on some gspca webcams from field reports.
168   // Put it as the least preferred format.
169   fourccs->push_back(V4L2_PIX_FMT_JPEG);
170 }
171
172 static bool HasUsableFormats(int fd) {
173   v4l2_fmtdesc fmtdesc;
174   std::list<int> usable_fourccs;
175
176   GetListOfUsableFourCCs(false, &usable_fourccs);
177
178   memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc));
179   fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
180
181   while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
182     if (std::find(usable_fourccs.begin(), usable_fourccs.end(),
183                   fmtdesc.pixelformat) != usable_fourccs.end())
184       return true;
185
186     fmtdesc.index++;
187   }
188   return false;
189 }
190
191 void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
192   int fd = -1;
193
194 #if defined(OS_TIZEN_MOBILE)
195   mfld_functions = &mfld_adv_ci;
196 #endif
197   mfld_driver_initialize(mfld_functions);
198
199   // Empty the name list.
200   device_names->clear();
201
202   base::FilePath path("/dev/");
203   const char* device_wildcards = mfld_library ? "video0" : "video*";
204   base::FileEnumerator enumerator(
205       path, false, base::FileEnumerator::FILES, device_wildcards);
206
207   while (!enumerator.Next().empty()) {
208     base::FileEnumerator::FileInfo info = enumerator.GetInfo();
209
210     std::string unique_id = path.value() + info.GetName().value();
211     if ((fd = open(unique_id.c_str() , O_RDONLY)) < 0) {
212       // Failed to open this device.
213       continue;
214     }
215     // Test if this is a V4L2 capture device.
216     v4l2_capability cap;
217     if ((ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) &&
218         (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
219       // Here chromium was expecting any capture, but not output video device.
220       // Unfortunately on Tizen camera is both a capture and output device.
221       if (!mfld_library && (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))
222         continue;
223       // This is a V4L2 video capture device
224       if (HasUsableFormats(fd)) {
225         Name device_name(base::StringPrintf("%s", cap.card), unique_id);
226         device_names->push_back(device_name);
227       } else {
228         DVLOG(1) << "No usable formats reported by " << info.GetName().value();
229       }
230     }
231     close(fd);
232   }
233 }
234
235 void VideoCaptureDevice::GetDeviceSupportedFormats(
236     const Name& device,
237     VideoCaptureCapabilities* formats) {
238
239   if (device.id().empty())
240     return;
241   int fd;
242   VideoCaptureCapabilities capture_formats;
243   if ((fd = open(device.id().c_str(), O_RDONLY)) < 0) {
244     // Failed to open this device.
245     return;
246   }
247
248   formats->clear();
249
250   VideoCaptureCapability capture_format;
251   // Retrieve the caps one by one, first get colorspace, then sizes, then
252   // framerates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference.
253   v4l2_fmtdesc pixel_format = {};
254   pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
255   while (ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format) == 0) {
256     capture_format.color =
257         V4l2ColorToVideoCaptureColorFormat((int32)pixel_format.pixelformat);
258     if (capture_format.color == PIXEL_FORMAT_UNKNOWN) continue;
259
260     v4l2_frmsizeenum frame_size = {};
261     frame_size.pixel_format = pixel_format.pixelformat;
262     while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0) {
263       if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
264         capture_format.width = frame_size.discrete.width;
265         capture_format.height = frame_size.discrete.height;
266       } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
267         // TODO(mcasas): see http://crbug.com/249953, support these devices.
268         NOTIMPLEMENTED();
269       } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
270         // TODO(mcasas): see http://crbug.com/249953, support these devices.
271         NOTIMPLEMENTED();
272       }
273       v4l2_frmivalenum frame_interval = {};
274       frame_interval.pixel_format = pixel_format.pixelformat;
275       frame_interval.width = frame_size.discrete.width;
276       frame_interval.height = frame_size.discrete.height;
277       while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval) == 0) {
278         if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
279           if (frame_interval.discrete.numerator != 0) {
280             capture_format.frame_rate =
281                 static_cast<float>(frame_interval.discrete.denominator) /
282                 static_cast<float>(frame_interval.discrete.numerator);
283           } else {
284             capture_format.frame_rate = 0;
285           }
286         } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
287           // TODO(mcasas): see http://crbug.com/249953, support these devices.
288           NOTIMPLEMENTED();
289           break;
290         } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
291           // TODO(mcasas): see http://crbug.com/249953, support these devices.
292           NOTIMPLEMENTED();
293           break;
294         }
295         formats->push_back(capture_format);
296         ++frame_interval.index;
297       }
298       ++frame_size.index;
299     }
300     ++pixel_format.index;
301   }
302
303   close(fd);
304   return;
305 }
306
307 static bool ReadIdFile(const std::string path, std::string* id) {
308   char id_buf[kVidPidSize];
309   FILE* file = fopen(path.c_str(), "rb");
310   if (!file)
311     return false;
312   const bool success = fread(id_buf, kVidPidSize, 1, file) == 1;
313   fclose(file);
314   if (!success)
315     return false;
316   id->append(id_buf, kVidPidSize);
317   return true;
318 }
319
320 const std::string VideoCaptureDevice::Name::GetModel() const {
321   // |unique_id| is of the form "/dev/video2".  |file_name| is "video2".
322   const std::string dev_dir = "/dev/";
323   DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir));
324   const std::string file_name =
325       unique_id_.substr(dev_dir.length(), unique_id_.length());
326
327   const std::string vidPath =
328       base::StringPrintf(kVidPathTemplate, file_name.c_str());
329   const std::string pidPath =
330       base::StringPrintf(kPidPathTemplate, file_name.c_str());
331
332   std::string usb_id;
333   if (!ReadIdFile(vidPath, &usb_id))
334     return "";
335   usb_id.append(":");
336   if (!ReadIdFile(pidPath, &usb_id))
337     return "";
338
339   return usb_id;
340 }
341
342 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
343   VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name);
344   if (!self)
345     return NULL;
346
347   // Test opening the device driver. This is to make sure it is available.
348   // We will reopen it again in our worker thread when someone
349   // allocates the camera.
350   int fd = open(device_name.id().c_str(), O_RDONLY);
351   if (fd < 0) {
352     DVLOG(1) << "Cannot open device";
353     delete self;
354     return NULL;
355   }
356   close(fd);
357
358   return self;
359 }
360
361 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name)
362     : state_(kIdle),
363       device_name_(device_name),
364       device_fd_(-1),
365       v4l2_thread_("V4L2Thread"),
366       buffer_pool_(NULL),
367       buffer_pool_size_(0),
368       timeout_count_(0) {}
369
370 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() {
371   state_ = kIdle;
372   // Check if the thread is running.
373   // This means that the device have not been DeAllocated properly.
374   DCHECK(!v4l2_thread_.IsRunning());
375
376   v4l2_thread_.Stop();
377   if (device_fd_ >= 0) {
378     close(device_fd_);
379   }
380 }
381
382 void VideoCaptureDeviceLinux::AllocateAndStart(
383     const VideoCaptureCapability& capture_format,
384     scoped_ptr<VideoCaptureDevice::Client> client) {
385   if (v4l2_thread_.IsRunning()) {
386     return;  // Wrong state.
387   }
388   v4l2_thread_.Start();
389   v4l2_thread_.message_loop()->PostTask(
390       FROM_HERE,
391       base::Bind(&VideoCaptureDeviceLinux::OnAllocateAndStart,
392                  base::Unretained(this),
393                  capture_format.width,
394                  capture_format.height,
395                  capture_format.frame_rate,
396                  base::Passed(&client)));
397 }
398
399 void VideoCaptureDeviceLinux::StopAndDeAllocate() {
400   if (!v4l2_thread_.IsRunning()) {
401     return;  // Wrong state.
402   }
403   v4l2_thread_.message_loop()->PostTask(
404       FROM_HERE,
405       base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate,
406                  base::Unretained(this)));
407   v4l2_thread_.Stop();
408   // Make sure no buffers are still allocated.
409   // This can happen (theoretically) if an error occurs when trying to stop
410   // the camera.
411   DeAllocateVideoBuffers();
412 }
413
414 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width,
415                                                  int height,
416                                                  int frame_rate,
417                                                  scoped_ptr<Client> client) {
418   DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
419
420   client_ = client.Pass();
421
422   // Need to open camera with O_RDWR after Linux kernel 3.3.
423   if ((device_fd_ = open(device_name_.id().c_str(), O_RDWR)) < 0) {
424     SetErrorState("Failed to open V4L2 device driver.");
425     return;
426   }
427
428   // Test if this is a V4L2 capture device.
429   v4l2_capability cap;
430   bool is_capture_device = (ioctl(device_fd_, VIDIOC_QUERYCAP, &cap) == 0) &&
431                            (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE);
432   bool is_output_device = cap.capabilities & V4L2_CAP_VIDEO_OUTPUT;
433   if (!is_capture_device || (!mfld_library && is_output_device)) {
434     // This is not a V4L2 video capture device.
435     close(device_fd_);
436     device_fd_ = -1;
437     SetErrorState("This is not a V4L2 video capture device");
438     return;
439   }
440
441   if (mfld_library) {
442     int camera_sensor = kCameraSensorSecondary;
443     if (ioctl(device_fd_, VIDIOC_S_INPUT, &camera_sensor) < 0) {
444       SetErrorState("Cannot select camera sensor");
445       return;
446     }
447     struct v4l2_input input;
448     memset(&input, 0, sizeof(input));
449     input.index = camera_sensor;
450     if (ioctl(device_fd_, VIDIOC_ENUMINPUT, &input) < 0) {
451       SetErrorState("Cannot enumerate camera input");
452       return;
453     }
454     char* name = reinterpret_cast<char *>(input.name);
455     if (char* space = strchr(name, ' '))
456       name[space - name] = '\0';
457     if (mfld_cam_driver_init(device_fd_, name)) {
458       SetErrorState("Cannot initialize libmfldcam");
459       return;
460     }
461     struct v4l2_control control;
462     memset(&control, 0, sizeof(control));
463     control.id = V4L2_CID_VFLIP;
464     control.value = 0;
465     if (ioctl(device_fd_, VIDIOC_S_CTRL, &control) < 0) {
466       SetErrorState("Cannot set vflip");
467       return;
468     }
469     control.id = V4L2_CID_HFLIP;
470     control.value = 0;
471     if (ioctl(device_fd_, VIDIOC_S_CTRL, &control) < 0) {
472       SetErrorState("Cannot set hflip");
473       return;
474     }
475     control.id = V4L2_CID_POWER_LINE_FREQUENCY;
476     // CAM_GENERAL_FLICKER_REDUCTION_MODE_50HZ
477     control.value = 1;
478     if (ioctl(device_fd_, VIDIOC_S_CTRL, &control) < 0) {
479       SetErrorState("Cannot set power line frequency");;
480       return;
481     }
482   }
483   // Get supported video formats in preferred order.
484   // For large resolutions, favour mjpeg over raw formats.
485   std::list<int> v4l2_formats;
486   GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight,
487                          &v4l2_formats);
488
489   v4l2_fmtdesc fmtdesc;
490   memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc));
491   fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
492
493   // Enumerate image formats.
494   std::list<int>::iterator best = v4l2_formats.end();
495   while (ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
496     best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat);
497     fmtdesc.index++;
498   }
499
500   if (best == v4l2_formats.end()) {
501     SetErrorState("Failed to find a supported camera format.");
502     return;
503   }
504
505   // Set format and frame size now.
506   v4l2_format video_fmt;
507   memset(&video_fmt, 0, sizeof(video_fmt));
508   video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
509   video_fmt.fmt.pix.sizeimage = 0;
510   video_fmt.fmt.pix.width = width;
511   video_fmt.fmt.pix.height = height;
512   video_fmt.fmt.pix.pixelformat = *best;
513
514   if (ioctl(device_fd_, VIDIOC_S_FMT, &video_fmt) < 0) {
515     SetErrorState("Failed to set camera format");
516     return;
517   }
518
519   if (mfld_library)
520     mfld_cam_set_capture_fmt(device_fd_, width, height, *best);
521
522   // Set capture framerate in the form of capture interval.
523   v4l2_streamparm streamparm;
524   memset(&streamparm, 0, sizeof(v4l2_streamparm));
525   streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
526   // The following line checks that the driver knows about framerate get/set.
527   if (ioctl(device_fd_, VIDIOC_G_PARM, &streamparm) >= 0) {
528     // Now check if the device is able to accept a capture framerate set.
529     if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
530       streamparm.parm.capture.timeperframe.numerator = 1;
531       streamparm.parm.capture.timeperframe.denominator =
532           (frame_rate) ? frame_rate : kTypicalFramerate;
533
534       if (ioctl(device_fd_, VIDIOC_S_PARM, &streamparm) < 0) {
535         SetErrorState("Failed to set camera framerate");
536         return;
537       }
538       DVLOG(2) << "Actual camera driverframerate: "
539                << streamparm.parm.capture.timeperframe.denominator << "/"
540                << streamparm.parm.capture.timeperframe.numerator;
541     }
542   }
543   // TODO(mcasas): what should be done if the camera driver does not allow
544   // framerate configuration, or the actual one is different from the desired?
545
546   // Store our current width and height.
547   VideoCaptureCapability current_settings;
548   current_settings.color = V4l2ColorToVideoCaptureColorFormat(
549       video_fmt.fmt.pix.pixelformat);
550   current_settings.width  = video_fmt.fmt.pix.width;
551   current_settings.height = video_fmt.fmt.pix.height;
552   current_settings.frame_rate = frame_rate;
553
554   // Report the resulting frame size to the client.
555   client_->OnFrameInfo(current_settings);
556
557   // Start capturing.
558   if (!AllocateVideoBuffers()) {
559     // Error, We can not recover.
560     SetErrorState("Allocate buffer failed");
561     return;
562   }
563
564   if (mfld_library)
565     mfld_cam_driver_set_mipi_interrupt(device_fd_, 1);
566
567   // Start UVC camera.
568   v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
569   if (ioctl(device_fd_, VIDIOC_STREAMON, &type) == -1) {
570     SetErrorState("VIDIOC_STREAMON failed");
571     return;
572   }
573
574   state_ = kCapturing;
575   // Post task to start fetching frames from v4l2.
576   v4l2_thread_.message_loop()->PostTask(
577       FROM_HERE,
578       base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
579                  base::Unretained(this)));
580 }
581
582 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() {
583   DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
584
585   v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
586   if (ioctl(device_fd_, VIDIOC_STREAMOFF, &type) < 0) {
587     SetErrorState("VIDIOC_STREAMOFF failed");
588     return;
589   }
590
591   if (mfld_library)
592     mfld_cam_driver_set_mipi_interrupt(device_fd_, 0);
593
594   // We don't dare to deallocate the buffers if we can't stop
595   // the capture device.
596   DeAllocateVideoBuffers();
597
598   if (mfld_library)
599     mfld_cam_driver_deinit(device_fd_);
600
601   // We need to close and open the device if we want to change the settings
602   // Otherwise VIDIOC_S_FMT will return error
603   // Sad but true.
604   close(device_fd_);
605   device_fd_ = -1;
606   state_ = kIdle;
607   client_.reset();
608 }
609
610 void VideoCaptureDeviceLinux::OnCaptureTask() {
611   DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
612
613   if (state_ != kCapturing) {
614     return;
615   }
616
617   fd_set r_set;
618   FD_ZERO(&r_set);
619   FD_SET(device_fd_, &r_set);
620   timeval timeout;
621
622   timeout.tv_sec = 0;
623   timeout.tv_usec = kCaptureTimeoutUs;
624
625   // First argument to select is the highest numbered file descriptor +1.
626   // Refer to http://linux.die.net/man/2/select for more information.
627   int result = select(device_fd_ + 1, &r_set, NULL, NULL, &timeout);
628   // Check if select have failed.
629   if (result < 0) {
630     // EINTR is a signal. This is not really an error.
631     if (errno != EINTR) {
632       SetErrorState("Select failed");
633       return;
634     }
635     v4l2_thread_.message_loop()->PostDelayedTask(
636         FROM_HERE,
637         base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
638                    base::Unretained(this)),
639         base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs));
640   }
641
642   // Check if select timeout.
643   if (result == 0) {
644     timeout_count_++;
645     if (timeout_count_ >= kContinuousTimeoutLimit) {
646       SetErrorState(base::StringPrintf(
647           "Continuous timeout %d times", timeout_count_));
648       timeout_count_ = 0;
649       return;
650     }
651   } else {
652     timeout_count_ = 0;
653   }
654
655   // Check if the driver have filled a buffer.
656   if (FD_ISSET(device_fd_, &r_set)) {
657     v4l2_buffer buffer;
658     memset(&buffer, 0, sizeof(buffer));
659     buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
660     buffer.memory = V4L2_MEMORY_MMAP;
661     // Dequeue a buffer.
662     if (ioctl(device_fd_, VIDIOC_DQBUF, &buffer) == 0) {
663       client_->OnIncomingCapturedFrame(
664           static_cast<uint8*> (buffer_pool_[buffer.index].start),
665           buffer.bytesused, base::Time::Now(), 0, false, false);
666
667       // Enqueue the buffer again.
668       if (ioctl(device_fd_, VIDIOC_QBUF, &buffer) == -1) {
669         SetErrorState(base::StringPrintf(
670             "Failed to enqueue capture buffer errno %d", errno));
671       }
672     } else {
673       SetErrorState(base::StringPrintf(
674           "Failed to dequeue capture buffer errno %d", errno));
675       return;
676     }
677   }
678
679   v4l2_thread_.message_loop()->PostTask(
680       FROM_HERE,
681       base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
682                  base::Unretained(this)));
683 }
684
685 bool VideoCaptureDeviceLinux::AllocateVideoBuffers() {
686   v4l2_requestbuffers r_buffer;
687   memset(&r_buffer, 0, sizeof(r_buffer));
688
689   r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
690   r_buffer.memory = V4L2_MEMORY_MMAP;
691   r_buffer.count = kMaxVideoBuffers;
692
693   if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) {
694     return false;
695   }
696
697   if (r_buffer.count > kMaxVideoBuffers) {
698     r_buffer.count = kMaxVideoBuffers;
699   }
700
701   buffer_pool_size_ = r_buffer.count;
702
703   // Map the buffers.
704   buffer_pool_ = new Buffer[r_buffer.count];
705   for (unsigned int i = 0; i < r_buffer.count; i++) {
706     v4l2_buffer buffer;
707     memset(&buffer, 0, sizeof(buffer));
708     buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
709     buffer.memory = V4L2_MEMORY_MMAP;
710     buffer.index = i;
711
712     if (ioctl(device_fd_, VIDIOC_QUERYBUF, &buffer) < 0) {
713       return false;
714     }
715
716     // Some devices require mmap() to be called with both READ and WRITE.
717     // See crbug.com/178582.
718     buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
719                                  MAP_SHARED, device_fd_, buffer.m.offset);
720     if (buffer_pool_[i].start == MAP_FAILED) {
721       return false;
722     }
723     buffer_pool_[i].length = buffer.length;
724     // Enqueue the buffer in the drivers incoming queue.
725     if (ioctl(device_fd_, VIDIOC_QBUF, &buffer) < 0) {
726       return false;
727     }
728   }
729   return true;
730 }
731
732 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() {
733   if (!buffer_pool_)
734     return;
735
736   // Unmaps buffers.
737   for (int i = 0; i < buffer_pool_size_; i++) {
738     munmap(buffer_pool_[i].start, buffer_pool_[i].length);
739   }
740   v4l2_requestbuffers r_buffer;
741   memset(&r_buffer, 0, sizeof(r_buffer));
742   r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
743   r_buffer.memory = V4L2_MEMORY_MMAP;
744   r_buffer.count = 0;
745
746   if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) {
747     SetErrorState("Failed to reset buf.");
748   }
749
750   delete [] buffer_pool_;
751   buffer_pool_ = NULL;
752   buffer_pool_size_ = 0;
753 }
754
755 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) {
756   DCHECK(!v4l2_thread_.IsRunning() ||
757          v4l2_thread_.message_loop() == base::MessageLoop::current());
758   DVLOG(1) << reason;
759   state_ = kError;
760   client_->OnError();
761 }
762
763 }  // namespace media