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

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

Issue 1031583002: Revert of Linux Video Capture: Add V4L2VideoCaptureDelegate{Single,Multi}Plane. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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>
7 #if defined(OS_OPENBSD) 10 #if defined(OS_OPENBSD)
8 #include <sys/videoio.h> 11 #include <sys/videoio.h>
9 #else 12 #else
10 #include <linux/videodev2.h> 13 #include <linux/videodev2.h>
11 #endif 14 #endif
15 #include <sys/ioctl.h>
16 #include <sys/mman.h>
12 17
13 #include <list> 18 #include <list>
14 #include <string> 19 #include <string>
15 20
16 #include "base/bind.h" 21 #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"
17 #include "base/strings/stringprintf.h" 25 #include "base/strings/stringprintf.h"
18 #include "media/video/capture/linux/v4l2_capture_delegate.h"
19 26
20 namespace media { 27 namespace media {
21 28
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
22 // USB VID and PID are both 4 bytes long. 102 // USB VID and PID are both 4 bytes long.
23 static const size_t kVidPidSize = 4; 103 static const size_t kVidPidSize = 4;
24 104
25 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding 105 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding
26 // USB device info directory. 106 // USB device info directory.
27 static const char kVidPathTemplate[] = 107 static const char kVidPathTemplate[] =
28 "/sys/class/video4linux/%s/device/../idVendor"; 108 "/sys/class/video4linux/%s/device/../idVendor";
29 static const char kPidPathTemplate[] = 109 static const char kPidPathTemplate[] =
30 "/sys/class/video4linux/%s/device/../idProduct"; 110 "/sys/class/video4linux/%s/device/../idProduct";
31 111
32 static bool ReadIdFile(const std::string path, std::string* id) { 112 static bool ReadIdFile(const std::string path, std::string* id) {
33 char id_buf[kVidPidSize]; 113 char id_buf[kVidPidSize];
34 FILE* file = fopen(path.c_str(), "rb"); 114 FILE* file = fopen(path.c_str(), "rb");
35 if (!file) 115 if (!file)
36 return false; 116 return false;
37 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1; 117 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1;
38 fclose(file); 118 fclose(file);
39 if (!success) 119 if (!success)
40 return false; 120 return false;
41 id->append(id_buf, kVidPidSize); 121 id->append(id_buf, kVidPidSize);
42 return true; 122 return true;
43 } 123 }
44 124
45 // Translates Video4Linux pixel formats to Chromium pixel formats. 125 // This function translates Video4Linux pixel formats to Chromium pixel formats,
126 // should only support those listed in GetListOfUsableFourCCs.
46 // static 127 // static
47 VideoPixelFormat VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat( 128 VideoPixelFormat VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat(
48 uint32 v4l2_fourcc) { 129 uint32 v4l2_fourcc) {
49 return V4L2CaptureDelegate::V4l2FourCcToChromiumPixelFormat(v4l2_fourcc); 130 const struct {
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;
50 } 150 }
51 151
52 // Gets a list of usable Four CC formats prioritised.
53 // static 152 // static
54 std::list<uint32_t> VideoCaptureDeviceLinux::GetListOfUsableFourCCs( 153 std::list<int> VideoCaptureDeviceLinux::GetListOfUsableFourCCs(
55 bool favour_mjpeg) { 154 bool favour_mjpeg) {
56 return V4L2CaptureDelegate::GetListOfUsableFourCcs(favour_mjpeg); 155 std::list<int> fourccs;
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;
57 } 167 }
58 168
59 const std::string VideoCaptureDevice::Name::GetModel() const { 169 const std::string VideoCaptureDevice::Name::GetModel() const {
60 // |unique_id| is of the form "/dev/video2". |file_name| is "video2". 170 // |unique_id| is of the form "/dev/video2". |file_name| is "video2".
61 const std::string dev_dir = "/dev/"; 171 const std::string dev_dir = "/dev/";
62 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir)); 172 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir));
63 const std::string file_name = 173 const std::string file_name =
64 unique_id_.substr(dev_dir.length(), unique_id_.length()); 174 unique_id_.substr(dev_dir.length(), unique_id_.length());
65 175
66 const std::string vidPath = 176 const std::string vidPath =
(...skipping 23 matching lines...) Expand all
90 v4l2_thread_.Stop(); 200 v4l2_thread_.Stop();
91 } 201 }
92 202
93 void VideoCaptureDeviceLinux::AllocateAndStart( 203 void VideoCaptureDeviceLinux::AllocateAndStart(
94 const VideoCaptureParams& params, 204 const VideoCaptureParams& params,
95 scoped_ptr<VideoCaptureDevice::Client> client) { 205 scoped_ptr<VideoCaptureDevice::Client> client) {
96 DCHECK(!capture_impl_); 206 DCHECK(!capture_impl_);
97 if (v4l2_thread_.IsRunning()) 207 if (v4l2_thread_.IsRunning())
98 return; // Wrong state. 208 return; // Wrong state.
99 v4l2_thread_.Start(); 209 v4l2_thread_.Start();
100 210 capture_impl_ = new V4L2CaptureDelegate(device_name_,
101 const int line_frequency = 211 v4l2_thread_.message_loop_proxy(),
102 TranslatePowerLineFrequencyToV4L2(GetPowerLineFrequencyForLocation()); 212 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 }
109 v4l2_thread_.message_loop()->PostTask( 213 v4l2_thread_.message_loop()->PostTask(
110 FROM_HERE, 214 FROM_HERE,
111 base::Bind(&V4L2CaptureDelegate::AllocateAndStart, capture_impl_, 215 base::Bind(
112 params.requested_format.frame_size.width(), 216 &VideoCaptureDeviceLinux::V4L2CaptureDelegate::AllocateAndStart,
113 params.requested_format.frame_size.height(), 217 capture_impl_,
114 params.requested_format.frame_rate, base::Passed(&client))); 218 params.requested_format.frame_size.width(),
219 params.requested_format.frame_size.height(),
220 params.requested_format.frame_rate,
221 base::Passed(&client)));
115 } 222 }
116 223
117 void VideoCaptureDeviceLinux::StopAndDeAllocate() { 224 void VideoCaptureDeviceLinux::StopAndDeAllocate() {
118 if (!v4l2_thread_.IsRunning()) 225 if (!v4l2_thread_.IsRunning())
119 return; // Wrong state. 226 return; // Wrong state.
120 v4l2_thread_.message_loop()->PostTask( 227 v4l2_thread_.message_loop()->PostTask(
121 FROM_HERE, 228 FROM_HERE,
122 base::Bind(&V4L2CaptureDelegate::StopAndDeAllocate, capture_impl_)); 229 base::Bind(
230 &VideoCaptureDeviceLinux::V4L2CaptureDelegate::StopAndDeAllocate,
231 capture_impl_));
123 v4l2_thread_.Stop(); 232 v4l2_thread_.Stop();
124 233 // TODO(mcasas): VCDLinux called DeAllocateVideoBuffers() a second time after
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();
125 capture_impl_ = NULL; 238 capture_impl_ = NULL;
126 } 239 }
127 240
128 void VideoCaptureDeviceLinux::SetRotation(int rotation) { 241 void VideoCaptureDeviceLinux::SetRotation(int rotation) {
129 if (v4l2_thread_.IsRunning()) { 242 if (v4l2_thread_.IsRunning()) {
130 v4l2_thread_.message_loop()->PostTask( 243 v4l2_thread_.message_loop()->PostTask(
131 FROM_HERE, base::Bind(&V4L2CaptureDelegate::SetRotation, 244 FROM_HERE,
132 capture_impl_, rotation)); 245 base::Bind(
133 } 246 &VideoCaptureDeviceLinux::V4L2CaptureDelegate::SetRotation,
134 } 247 capture_impl_,
135 248 rotation));
136 // static 249 }
137 int VideoCaptureDeviceLinux::TranslatePowerLineFrequencyToV4L2(int frequency) { 250 }
138 switch (frequency) { 251
139 case kPowerLine50Hz: 252 VideoCaptureDeviceLinux::V4L2CaptureDelegate::V4L2CaptureDelegate(
140 return V4L2_CID_POWER_LINE_FREQUENCY_50HZ; 253 const Name& device_name,
141 case kPowerLine60Hz: 254 const scoped_refptr<base::SingleThreadTaskRunner> v4l2_task_runner,
142 return V4L2_CID_POWER_LINE_FREQUENCY_60HZ; 255 int power_line_frequency)
143 default: 256 : v4l2_task_runner_(v4l2_task_runner),
144 // If we have no idea of the frequency, at least try and set it to AUTO. 257 is_capturing_(false),
145 return V4L2_CID_POWER_LINE_FREQUENCY_AUTO; 258 device_name_(device_name),
146 } 259 buffer_pool_(NULL),
260 buffer_pool_size_(0),
261 timeout_count_(0),
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 }
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);
147 } 532 }
148 533
149 } // namespace media 534 } // 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