Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(338)

Side by Side Diff: media/video/capture/linux/video_capture_device_linux.cc

Issue 967793002: Linux Video Capture: Add V4L2VideoCaptureDelegate{Single,Multi}Plane. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: magjed@ comments Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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>
8 #include <fcntl.h>
9 #include <poll.h>
10 #if defined(OS_OPENBSD) 7 #if defined(OS_OPENBSD)
11 #include <sys/videoio.h> 8 #include <sys/videoio.h>
12 #else 9 #else
13 #include <linux/videodev2.h> 10 #include <linux/videodev2.h>
14 #endif 11 #endif
15 #include <sys/ioctl.h>
16 #include <sys/mman.h>
17 12
18 #include <list> 13 #include <list>
19 #include <string> 14 #include <string>
20 15
21 #include "base/bind.h" 16 #include "base/bind.h"
22 #include "base/files/file_enumerator.h"
23 #include "base/files/scoped_file.h"
24 #include "base/posix/eintr_wrapper.h"
25 #include "base/strings/stringprintf.h" 17 #include "base/strings/stringprintf.h"
18 #include "media/video/capture/linux/v4l2_capture_delegate.h"
26 19
27 namespace media { 20 namespace media {
28 21
29 #define GET_V4L2_FOURCC_CHAR(a, index) ((char)( ((a) >> (8 * index)) & 0xff))
30
31 // Desired number of video buffers to allocate. The actual number of allocated
32 // buffers by v4l2 driver can be higher or lower than this number.
33 // kNumVideoBuffers should not be too small, or Chrome may not return enough
34 // buffers back to driver in time.
35 const uint32 kNumVideoBuffers = 4;
36 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw.
37 enum { kCaptureTimeoutMs = 200 };
38 // The number of continuous timeouts tolerated before treated as error.
39 enum { kContinuousTimeoutLimit = 10 };
40 // MJPEG is preferred if the width or height is larger than this.
41 enum { kMjpegWidth = 640 };
42 enum { kMjpegHeight = 480 };
43 // Typical framerate, in fps
44 enum { kTypicalFramerate = 30 };
45
46 class VideoCaptureDeviceLinux::V4L2CaptureDelegate
47 : public base::RefCountedThreadSafe<V4L2CaptureDelegate>{
48 public:
49 V4L2CaptureDelegate(
50 const Name& device_name,
51 const scoped_refptr<base::SingleThreadTaskRunner> v4l2_task_runner,
52 int power_line_frequency);
53
54 void AllocateAndStart(int width,
55 int height,
56 float frame_rate,
57 scoped_ptr<Client> client);
58 void StopAndDeAllocate();
59 void SetRotation(int rotation);
60 bool DeAllocateVideoBuffers();
61
62 private:
63 // Buffers used to receive captured frames from v4l2.
64 struct Buffer {
65 Buffer() : start(0), length(0) {}
66 void* start;
67 size_t length;
68 };
69
70 friend class base::RefCountedThreadSafe<V4L2CaptureDelegate>;
71 ~V4L2CaptureDelegate();
72
73 void DoCapture();
74 bool AllocateVideoBuffers();
75 void SetErrorState(const std::string& reason);
76
77 const scoped_refptr<base::SingleThreadTaskRunner> v4l2_task_runner_;
78
79 bool is_capturing_;
80 scoped_ptr<VideoCaptureDevice::Client> client_;
81 const Name device_name_;
82 base::ScopedFD device_fd_; // File descriptor for the opened camera device.
83 Buffer* buffer_pool_;
84 int buffer_pool_size_; // Number of allocated buffers.
85 int timeout_count_;
86 VideoCaptureFormat capture_format_;
87 const int power_line_frequency_;
88
89 // Clockwise rotation in degrees. This value should be 0, 90, 180, or 270.
90 int rotation_;
91
92 DISALLOW_IMPLICIT_CONSTRUCTORS(V4L2CaptureDelegate);
93 };
94
95 // V4L2 color formats VideoCaptureDeviceLinux support.
96 static const int32 kV4l2RawFmts[] = {
97 V4L2_PIX_FMT_YUV420,
98 V4L2_PIX_FMT_YUYV,
99 V4L2_PIX_FMT_UYVY
100 };
101
102 // USB VID and PID are both 4 bytes long. 22 // USB VID and PID are both 4 bytes long.
103 static const size_t kVidPidSize = 4; 23 static const size_t kVidPidSize = 4;
104 24
105 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding 25 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding
106 // USB device info directory. 26 // USB device info directory.
107 static const char kVidPathTemplate[] = 27 static const char kVidPathTemplate[] =
108 "/sys/class/video4linux/%s/device/../idVendor"; 28 "/sys/class/video4linux/%s/device/../idVendor";
109 static const char kPidPathTemplate[] = 29 static const char kPidPathTemplate[] =
110 "/sys/class/video4linux/%s/device/../idProduct"; 30 "/sys/class/video4linux/%s/device/../idProduct";
111 31
112 static bool ReadIdFile(const std::string path, std::string* id) { 32 static bool ReadIdFile(const std::string path, std::string* id) {
113 char id_buf[kVidPidSize]; 33 char id_buf[kVidPidSize];
114 FILE* file = fopen(path.c_str(), "rb"); 34 FILE* file = fopen(path.c_str(), "rb");
115 if (!file) 35 if (!file)
116 return false; 36 return false;
117 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1; 37 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1;
118 fclose(file); 38 fclose(file);
119 if (!success) 39 if (!success)
120 return false; 40 return false;
121 id->append(id_buf, kVidPidSize); 41 id->append(id_buf, kVidPidSize);
122 return true; 42 return true;
123 } 43 }
124 44
125 // This function translates Video4Linux pixel formats to Chromium pixel formats, 45 // Translates Video4Linux pixel formats to Chromium pixel formats.
126 // should only support those listed in GetListOfUsableFourCCs.
127 // static 46 // static
128 VideoPixelFormat VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( 47 VideoPixelFormat VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat(
129 uint32 v4l2_fourcc) { 48 uint32 v4l2_fourcc) {
130 const struct { 49 return V4L2CaptureDelegate::V4l2FourCcToChromiumPixelFormat(v4l2_fourcc);
131 uint32 fourcc;
132 VideoPixelFormat pixel_format;
133 } kFourCcAndChromiumPixelFormat[] = {
134 {V4L2_PIX_FMT_YUV420, PIXEL_FORMAT_I420},
135 {V4L2_PIX_FMT_YUYV, PIXEL_FORMAT_YUY2},
136 {V4L2_PIX_FMT_UYVY, PIXEL_FORMAT_UYVY},
137 {V4L2_PIX_FMT_MJPEG, PIXEL_FORMAT_MJPEG},
138 {V4L2_PIX_FMT_JPEG, PIXEL_FORMAT_MJPEG},
139 };
140 for (const auto& fourcc_and_pixel_format : kFourCcAndChromiumPixelFormat) {
141 if (fourcc_and_pixel_format.fourcc == v4l2_fourcc)
142 return fourcc_and_pixel_format.pixel_format;
143 }
144 DVLOG(1) << "Unsupported pixel format: "
145 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 0)
146 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 1)
147 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 2)
148 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 3);
149 return PIXEL_FORMAT_UNKNOWN;
150 } 50 }
151 51
52 // Gets a list of usable Four CC formats prioritised.
152 // static 53 // static
153 std::list<int> VideoCaptureDeviceLinux::GetListOfUsableFourCCs( 54 std::list<uint32_t> VideoCaptureDeviceLinux::GetListOfUsableFourCCs(
154 bool favour_mjpeg) { 55 bool favour_mjpeg) {
155 std::list<int> fourccs; 56 return V4L2CaptureDelegate::GetListOfUsableFourCcs(favour_mjpeg);
156 for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i)
157 fourccs.push_back(kV4l2RawFmts[i]);
158 if (favour_mjpeg)
159 fourccs.push_front(V4L2_PIX_FMT_MJPEG);
160 else
161 fourccs.push_back(V4L2_PIX_FMT_MJPEG);
162
163 // JPEG works as MJPEG on some gspca webcams from field reports.
164 // Put it as the least preferred format.
165 fourccs.push_back(V4L2_PIX_FMT_JPEG);
166 return fourccs;
167 } 57 }
168 58
169 const std::string VideoCaptureDevice::Name::GetModel() const { 59 const std::string VideoCaptureDevice::Name::GetModel() const {
170 // |unique_id| is of the form "/dev/video2". |file_name| is "video2". 60 // |unique_id| is of the form "/dev/video2". |file_name| is "video2".
171 const std::string dev_dir = "/dev/"; 61 const std::string dev_dir = "/dev/";
172 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir)); 62 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir));
173 const std::string file_name = 63 const std::string file_name =
174 unique_id_.substr(dev_dir.length(), unique_id_.length()); 64 unique_id_.substr(dev_dir.length(), unique_id_.length());
175 65
176 const std::string vidPath = 66 const std::string vidPath =
(...skipping 23 matching lines...) Expand all
200 v4l2_thread_.Stop(); 90 v4l2_thread_.Stop();
201 } 91 }
202 92
203 void VideoCaptureDeviceLinux::AllocateAndStart( 93 void VideoCaptureDeviceLinux::AllocateAndStart(
204 const VideoCaptureParams& params, 94 const VideoCaptureParams& params,
205 scoped_ptr<VideoCaptureDevice::Client> client) { 95 scoped_ptr<VideoCaptureDevice::Client> client) {
206 DCHECK(!capture_impl_); 96 DCHECK(!capture_impl_);
207 if (v4l2_thread_.IsRunning()) 97 if (v4l2_thread_.IsRunning())
208 return; // Wrong state. 98 return; // Wrong state.
209 v4l2_thread_.Start(); 99 v4l2_thread_.Start();
210 capture_impl_ = new V4L2CaptureDelegate(device_name_, 100
211 v4l2_thread_.message_loop_proxy(), 101 const int line_frequency =
212 GetPowerLineFrequencyForLocation()); 102 TranslatePowerLineFrequencyToV4L2(GetPowerLineFrequencyForLocation());
103 capture_impl_ = V4L2CaptureDelegate::CreateV4L2CaptureDelegate(
104 device_name_, v4l2_thread_.message_loop_proxy(), line_frequency);
105 if (!capture_impl_) {
106 client->OnError("Failed to create VideoCaptureDelegate");
107 return;
108 }
213 v4l2_thread_.message_loop()->PostTask( 109 v4l2_thread_.message_loop()->PostTask(
214 FROM_HERE, 110 FROM_HERE,
215 base::Bind( 111 base::Bind(&V4L2CaptureDelegate::AllocateAndStart, capture_impl_,
216 &VideoCaptureDeviceLinux::V4L2CaptureDelegate::AllocateAndStart, 112 params.requested_format.frame_size.width(),
217 capture_impl_, 113 params.requested_format.frame_size.height(),
218 params.requested_format.frame_size.width(), 114 params.requested_format.frame_rate, base::Passed(&client)));
219 params.requested_format.frame_size.height(),
220 params.requested_format.frame_rate,
221 base::Passed(&client)));
222 } 115 }
223 116
224 void VideoCaptureDeviceLinux::StopAndDeAllocate() { 117 void VideoCaptureDeviceLinux::StopAndDeAllocate() {
225 if (!v4l2_thread_.IsRunning()) 118 if (!v4l2_thread_.IsRunning())
226 return; // Wrong state. 119 return; // Wrong state.
227 v4l2_thread_.message_loop()->PostTask( 120 v4l2_thread_.message_loop()->PostTask(
228 FROM_HERE, 121 FROM_HERE,
229 base::Bind( 122 base::Bind(&V4L2CaptureDelegate::StopAndDeAllocate, capture_impl_));
230 &VideoCaptureDeviceLinux::V4L2CaptureDelegate::StopAndDeAllocate,
231 capture_impl_));
232 v4l2_thread_.Stop(); 123 v4l2_thread_.Stop();
233 // TODO(mcasas): VCDLinux called DeAllocateVideoBuffers() a second time after 124
234 // stopping |v4l2_thread_| to make sure buffers were completely deallocated.
235 // Investigate if that's needed, otherwise remove the following line and make
236 // V4L2CaptureDelegate::DeAllocateVideoBuffers() private.
237 capture_impl_->DeAllocateVideoBuffers();
238 capture_impl_ = NULL; 125 capture_impl_ = NULL;
239 } 126 }
240 127
241 void VideoCaptureDeviceLinux::SetRotation(int rotation) { 128 void VideoCaptureDeviceLinux::SetRotation(int rotation) {
242 if (v4l2_thread_.IsRunning()) { 129 if (v4l2_thread_.IsRunning()) {
243 v4l2_thread_.message_loop()->PostTask( 130 v4l2_thread_.message_loop()->PostTask(
244 FROM_HERE, 131 FROM_HERE, base::Bind(&V4L2CaptureDelegate::SetRotation,
245 base::Bind( 132 capture_impl_, rotation));
246 &VideoCaptureDeviceLinux::V4L2CaptureDelegate::SetRotation,
247 capture_impl_,
248 rotation));
249 } 133 }
250 } 134 }
251 135
252 VideoCaptureDeviceLinux::V4L2CaptureDelegate::V4L2CaptureDelegate( 136 // static
253 const Name& device_name, 137 int VideoCaptureDeviceLinux::TranslatePowerLineFrequencyToV4L2(int frequency) {
254 const scoped_refptr<base::SingleThreadTaskRunner> v4l2_task_runner, 138 switch (frequency) {
255 int power_line_frequency) 139 case kPowerLine50Hz:
256 : v4l2_task_runner_(v4l2_task_runner), 140 return V4L2_CID_POWER_LINE_FREQUENCY_50HZ;
257 is_capturing_(false), 141 case kPowerLine60Hz:
258 device_name_(device_name), 142 return V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
259 buffer_pool_(NULL), 143 default:
260 buffer_pool_size_(0), 144 // If we have no idea of the frequency, at least try and set it to AUTO.
261 timeout_count_(0), 145 return V4L2_CID_POWER_LINE_FREQUENCY_AUTO;
262 power_line_frequency_(power_line_frequency),
263 rotation_(0) {
264 }
265
266 VideoCaptureDeviceLinux::V4L2CaptureDelegate::~V4L2CaptureDelegate() {
267 DCHECK(!client_);
268 }
269
270 void VideoCaptureDeviceLinux::V4L2CaptureDelegate::AllocateAndStart(
271 int width,
272 int height,
273 float frame_rate,
274 scoped_ptr<Client> client) {
275 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
276 DCHECK(client);
277 client_ = client.Pass();
278
279 // Need to open camera with O_RDWR after Linux kernel 3.3.
280 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR)));
281 if (!device_fd_.is_valid()) {
282 SetErrorState("Failed to open V4L2 device driver file.");
283 return;
284 } 146 }
285
286 v4l2_capability cap = {};
287 if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
288 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE &&
289 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)))) {
290 device_fd_.reset();
291 SetErrorState("This is not a V4L2 video capture device");
292 return;
293 }
294
295 // Get supported video formats in preferred order.
296 // For large resolutions, favour mjpeg over raw formats.
297 const std::list<int>& desired_v4l2_formats =
298 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight);
299 std::list<int>::const_iterator best = desired_v4l2_formats.end();
300
301 v4l2_fmtdesc fmtdesc = {};
302 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
303 for (; HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == 0;
304 ++fmtdesc.index) {
305 best = std::find(desired_v4l2_formats.begin(), best, fmtdesc.pixelformat);
306 }
307 if (best == desired_v4l2_formats.end()) {
308 SetErrorState("Failed to find a supported camera format.");
309 return;
310 }
311
312 v4l2_format video_fmt = {};
313 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
314 video_fmt.fmt.pix.sizeimage = 0;
315 video_fmt.fmt.pix.width = width;
316 video_fmt.fmt.pix.height = height;
317 video_fmt.fmt.pix.pixelformat = *best;
318 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt)) < 0) {
319 SetErrorState("Failed to set video capture format");
320 return;
321 }
322
323 // Set capture framerate in the form of capture interval.
324 v4l2_streamparm streamparm = {};
325 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
326 // The following line checks that the driver knows about framerate get/set.
327 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) {
328 // Now check if the device is able to accept a capture framerate set.
329 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
330 // |frame_rate| is float, approximate by a fraction.
331 streamparm.parm.capture.timeperframe.numerator =
332 media::kFrameRatePrecision;
333 streamparm.parm.capture.timeperframe.denominator = (frame_rate) ?
334 (frame_rate * media::kFrameRatePrecision) :
335 (kTypicalFramerate * media::kFrameRatePrecision);
336
337 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) <
338 0) {
339 SetErrorState("Failed to set camera framerate");
340 return;
341 }
342 DVLOG(2) << "Actual camera driverframerate: "
343 << streamparm.parm.capture.timeperframe.denominator << "/"
344 << streamparm.parm.capture.timeperframe.numerator;
345 }
346 }
347 // TODO(mcasas): what should be done if the camera driver does not allow
348 // framerate configuration, or the actual one is different from the desired?
349
350 // Set anti-banding/anti-flicker to 50/60Hz. May fail due to not supported
351 // operation (|errno| == EINVAL in this case) or plain failure.
352 if ((power_line_frequency_ == kPowerLine50Hz) ||
353 (power_line_frequency_ == kPowerLine60Hz)) {
354 struct v4l2_control control = {};
355 control.id = V4L2_CID_POWER_LINE_FREQUENCY;
356 control.value = (power_line_frequency_ == kPowerLine50Hz)
357 ? V4L2_CID_POWER_LINE_FREQUENCY_50HZ
358 : V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
359 HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control));
360 }
361
362 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width,
363 video_fmt.fmt.pix.height);
364 capture_format_.frame_rate = frame_rate;
365 capture_format_.pixel_format =
366 V4l2FourCcToChromiumPixelFormat(video_fmt.fmt.pix.pixelformat);
367
368 if (!AllocateVideoBuffers()) {
369 SetErrorState("Allocate buffer failed (Cannot recover from this error)");
370 return;
371 }
372
373 const v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
374 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) < 0) {
375 SetErrorState("VIDIOC_STREAMON failed");
376 return;
377 }
378
379 is_capturing_ = true;
380 // Post task to start fetching frames from v4l2.
381 v4l2_task_runner_->PostTask(
382 FROM_HERE,
383 base::Bind(&VideoCaptureDeviceLinux::V4L2CaptureDelegate::DoCapture,
384 this));
385 }
386
387 void VideoCaptureDeviceLinux::V4L2CaptureDelegate::StopAndDeAllocate() {
388 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
389
390 const v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
391 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) {
392 SetErrorState("VIDIOC_STREAMOFF failed");
393 return;
394 }
395 // We don't dare to deallocate the buffers if we can't stop the capture
396 // device.
397 if (!DeAllocateVideoBuffers())
398 SetErrorState("Failed to reset buffers");
399
400 // We need to close and open the device if we want to change the settings.
401 // Otherwise VIDIOC_S_FMT will return error. Sad but true.
402 device_fd_.reset();
403 is_capturing_ = false;
404 client_.reset();
405 }
406
407 void VideoCaptureDeviceLinux::V4L2CaptureDelegate::SetRotation(int rotation) {
408 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
409 DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
410 rotation_ = rotation;
411 }
412
413 void VideoCaptureDeviceLinux::V4L2CaptureDelegate::DoCapture() {
414 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
415 if (!is_capturing_)
416 return;
417
418 pollfd device_pfd = {};
419 device_pfd.fd = device_fd_.get();
420 device_pfd.events = POLLIN;
421 const int result = HANDLE_EINTR(poll(&device_pfd, 1, kCaptureTimeoutMs));
422 if (result < 0) {
423 SetErrorState("Poll failed");
424 return;
425 }
426 // Check if poll() timed out; track the amount of times it did in a row and
427 // throw an error if it times out too many times.
428 if (result == 0) {
429 timeout_count_++;
430 if (timeout_count_ >= kContinuousTimeoutLimit) {
431 SetErrorState("Multiple continuous timeouts while read-polling.");
432 timeout_count_ = 0;
433 return;
434 }
435 } else {
436 timeout_count_ = 0;
437 }
438
439 // Check if the driver has filled a buffer.
440 if (device_pfd.revents & POLLIN) {
441 v4l2_buffer buffer = {};
442 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
443 buffer.memory = V4L2_MEMORY_MMAP;
444 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < 0) {
445 SetErrorState("Failed to dequeue capture buffer");
446 return;
447 }
448 client_->OnIncomingCapturedData(
449 static_cast<uint8*>(buffer_pool_[buffer.index].start),
450 buffer.bytesused,
451 capture_format_,
452 rotation_,
453 base::TimeTicks::Now());
454
455 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0)
456 SetErrorState("Failed to enqueue capture buffer");
457 }
458
459 v4l2_task_runner_->PostTask(
460 FROM_HERE,
461 base::Bind(&VideoCaptureDeviceLinux::V4L2CaptureDelegate::DoCapture,
462 this));
463 }
464
465 bool VideoCaptureDeviceLinux::V4L2CaptureDelegate::AllocateVideoBuffers() {
466 v4l2_requestbuffers r_buffer = {};
467 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
468 r_buffer.memory = V4L2_MEMORY_MMAP;
469 r_buffer.count = kNumVideoBuffers;
470 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
471 DLOG(ERROR) << "Error requesting MMAP buffers from V4L2";
472 return false;
473 }
474 buffer_pool_size_ = r_buffer.count;
475 buffer_pool_ = new Buffer[buffer_pool_size_];
476 for (unsigned int i = 0; i < r_buffer.count; ++i) {
477 v4l2_buffer buffer = {};
478 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
479 buffer.memory = V4L2_MEMORY_MMAP;
480 buffer.index = i;
481 buffer.length = 1;
482 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
483 DLOG(ERROR) << "Error querying status of a MMAP V4L2 buffer";
484 return false;
485 }
486
487 // Some devices require mmap() to be called with both READ and WRITE.
488 // See http://crbug.com/178582.
489 buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
490 MAP_SHARED, device_fd_.get(), buffer.m.offset);
491 if (buffer_pool_[i].start == MAP_FAILED) {
492 DLOG(ERROR) << "Error mmmap()ing a V4L2 buffer into userspace";
493 return false;
494 }
495
496 buffer_pool_[i].length = buffer.length;
497 // Enqueue the buffer in the drivers incoming queue.
498 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
499 DLOG(ERROR)
500 << "Error enqueuing a V4L2 buffer back to the drivers incoming queue";
501 return false;
502 }
503 }
504 return true;
505 }
506
507 bool VideoCaptureDeviceLinux::V4L2CaptureDelegate::DeAllocateVideoBuffers() {
508 if (!buffer_pool_)
509 return true;
510
511 for (int i = 0; i < buffer_pool_size_; ++i)
512 munmap(buffer_pool_[i].start, buffer_pool_[i].length);
513
514 v4l2_requestbuffers r_buffer = {};
515 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
516 r_buffer.memory = V4L2_MEMORY_MMAP;
517 r_buffer.count = 0;
518 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
519 return false;
520
521 delete [] buffer_pool_;
522 buffer_pool_ = NULL;
523 buffer_pool_size_ = 0;
524 return true;
525 }
526
527 void VideoCaptureDeviceLinux::V4L2CaptureDelegate::SetErrorState(
528 const std::string& reason) {
529 DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
530 is_capturing_ = false;
531 client_->OnError(reason);
532 } 147 }
533 148
534 } // namespace media 149 } // namespace media
OLDNEW
« no previous file with comments | « media/video/capture/linux/video_capture_device_linux.h ('k') | media/video/capture/video_capture_device.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698