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

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

Issue 191673003: Implement ScopedFD in terms of ScopedGeneric. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 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 | Annotate | Revision Log
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> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #if defined(OS_OPENBSD) 9 #if defined(OS_OPENBSD)
10 #include <sys/videoio.h> 10 #include <sys/videoio.h>
11 #else 11 #else
12 #include <linux/videodev2.h> 12 #include <linux/videodev2.h>
13 #endif 13 #endif
14 #include <sys/ioctl.h> 14 #include <sys/ioctl.h>
15 #include <sys/mman.h> 15 #include <sys/mman.h>
16 16
17 #include <list> 17 #include <list>
18 #include <string> 18 #include <string>
19 19
20 #include "base/bind.h" 20 #include "base/bind.h"
21 #include "base/files/file_enumerator.h" 21 #include "base/files/file_enumerator.h"
22 #include "base/files/scoped_file.h"
22 #include "base/posix/eintr_wrapper.h" 23 #include "base/posix/eintr_wrapper.h"
23 #include "base/strings/stringprintf.h" 24 #include "base/strings/stringprintf.h"
24 25
25 namespace media { 26 namespace media {
26 27
27 // Max number of video buffers VideoCaptureDeviceLinux can allocate. 28 // Max number of video buffers VideoCaptureDeviceLinux can allocate.
28 enum { kMaxVideoBuffers = 2 }; 29 enum { kMaxVideoBuffers = 2 };
29 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw. 30 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw.
30 enum { kCaptureTimeoutUs = 200000 }; 31 enum { kCaptureTimeoutUs = 200000 };
31 // The number of continuous timeouts tolerated before treated as error. 32 // The number of continuous timeouts tolerated before treated as error.
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { 113 void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
113 DCHECK(device_names->empty()); 114 DCHECK(device_names->empty());
114 base::FilePath path("/dev/"); 115 base::FilePath path("/dev/");
115 base::FileEnumerator enumerator( 116 base::FileEnumerator enumerator(
116 path, false, base::FileEnumerator::FILES, "video*"); 117 path, false, base::FileEnumerator::FILES, "video*");
117 118
118 while (!enumerator.Next().empty()) { 119 while (!enumerator.Next().empty()) {
119 base::FileEnumerator::FileInfo info = enumerator.GetInfo(); 120 base::FileEnumerator::FileInfo info = enumerator.GetInfo();
120 121
121 std::string unique_id = path.value() + info.GetName().value(); 122 std::string unique_id = path.value() + info.GetName().value();
122 int fd; 123 base::ScopedFD fd(HANDLE_EINTR(open(unique_id.c_str(), O_RDONLY)));
123 if ((fd = HANDLE_EINTR(open(unique_id.c_str() , O_RDONLY))) < 0) { 124 if (!fd.is_valid()) {
124 // Failed to open this device. 125 // Failed to open this device.
125 continue; 126 continue;
126 } 127 }
127 file_util::ScopedFD fd_closer(&fd);
128 // Test if this is a V4L2 capture device. 128 // Test if this is a V4L2 capture device.
129 v4l2_capability cap; 129 v4l2_capability cap;
130 if ((HANDLE_EINTR(ioctl(fd, VIDIOC_QUERYCAP, &cap)) == 0) && 130 if ((HANDLE_EINTR(ioctl(fd.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
131 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && 131 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) &&
132 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { 132 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) {
133 // This is a V4L2 video capture device 133 // This is a V4L2 video capture device
134 if (HasUsableFormats(fd)) { 134 if (HasUsableFormats(fd.get())) {
135 Name device_name(base::StringPrintf("%s", cap.card), unique_id); 135 Name device_name(base::StringPrintf("%s", cap.card), unique_id);
136 device_names->push_back(device_name); 136 device_names->push_back(device_name);
137 } else { 137 } else {
138 DVLOG(1) << "No usable formats reported by " << info.GetName().value(); 138 DVLOG(1) << "No usable formats reported by " << info.GetName().value();
139 } 139 }
140 } 140 }
141 } 141 }
142 } 142 }
143 143
144 void VideoCaptureDevice::GetDeviceSupportedFormats( 144 void VideoCaptureDevice::GetDeviceSupportedFormats(
145 const Name& device, 145 const Name& device,
146 VideoCaptureFormats* supported_formats) { 146 VideoCaptureFormats* supported_formats) {
147 if (device.id().empty()) 147 if (device.id().empty())
148 return; 148 return;
149 int fd; 149 base::ScopedFD fd(HANDLE_EINTR(open(device.id().c_str(), O_RDONLY)));
150 if ((fd = HANDLE_EINTR(open(device.id().c_str(), O_RDONLY))) < 0) { 150 if (!fd.is_valid()) {
151 // Failed to open this device. 151 // Failed to open this device.
152 return; 152 return;
153 } 153 }
154 file_util::ScopedFD fd_closer(&fd);
155 supported_formats->clear(); 154 supported_formats->clear();
156 155
157 // Retrieve the caps one by one, first get pixel format, then sizes, then 156 // Retrieve the caps one by one, first get pixel format, then sizes, then
158 // frame rates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. 157 // frame rates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference.
159 v4l2_fmtdesc pixel_format = {}; 158 v4l2_fmtdesc pixel_format = {};
160 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 159 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
161 while (HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format)) == 0) { 160 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FMT, &pixel_format)) == 0) {
162 VideoCaptureFormat supported_format; 161 VideoCaptureFormat supported_format;
163 supported_format.pixel_format = 162 supported_format.pixel_format =
164 V4l2ColorToVideoCaptureColorFormat((int32)pixel_format.pixelformat); 163 V4l2ColorToVideoCaptureColorFormat((int32)pixel_format.pixelformat);
165 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) { 164 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) {
166 ++pixel_format.index; 165 ++pixel_format.index;
167 continue; 166 continue;
168 } 167 }
169 168
170 v4l2_frmsizeenum frame_size = {}; 169 v4l2_frmsizeenum frame_size = {};
171 frame_size.pixel_format = pixel_format.pixelformat; 170 frame_size.pixel_format = pixel_format.pixelformat;
172 while (HANDLE_EINTR(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size)) == 0) { 171 while (HANDLE_EINTR(ioctl(fd.get(), VIDIOC_ENUM_FRAMESIZES, &frame_size)) ==
172 0) {
173 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { 173 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
174 supported_format.frame_size.SetSize( 174 supported_format.frame_size.SetSize(
175 frame_size.discrete.width, frame_size.discrete.height); 175 frame_size.discrete.width, frame_size.discrete.height);
176 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { 176 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
177 // TODO(mcasas): see http://crbug.com/249953, support these devices. 177 // TODO(mcasas): see http://crbug.com/249953, support these devices.
178 NOTIMPLEMENTED(); 178 NOTIMPLEMENTED();
179 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { 179 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
180 // TODO(mcasas): see http://crbug.com/249953, support these devices. 180 // TODO(mcasas): see http://crbug.com/249953, support these devices.
181 NOTIMPLEMENTED(); 181 NOTIMPLEMENTED();
182 } 182 }
183 v4l2_frmivalenum frame_interval = {}; 183 v4l2_frmivalenum frame_interval = {};
184 frame_interval.pixel_format = pixel_format.pixelformat; 184 frame_interval.pixel_format = pixel_format.pixelformat;
185 frame_interval.width = frame_size.discrete.width; 185 frame_interval.width = frame_size.discrete.width;
186 frame_interval.height = frame_size.discrete.height; 186 frame_interval.height = frame_size.discrete.height;
187 while (HANDLE_EINTR( 187 while (HANDLE_EINTR(ioctl(
188 ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) == 0) { 188 fd.get(), VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval)) == 0) {
189 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { 189 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
190 if (frame_interval.discrete.numerator != 0) { 190 if (frame_interval.discrete.numerator != 0) {
191 supported_format.frame_rate = 191 supported_format.frame_rate =
192 static_cast<float>(frame_interval.discrete.denominator) / 192 static_cast<float>(frame_interval.discrete.denominator) /
193 static_cast<float>(frame_interval.discrete.numerator); 193 static_cast<float>(frame_interval.discrete.numerator);
194 } else { 194 } else {
195 supported_format.frame_rate = 0; 195 supported_format.frame_rate = 0;
196 } 196 }
197 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { 197 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
198 // TODO(mcasas): see http://crbug.com/249953, support these devices. 198 // TODO(mcasas): see http://crbug.com/249953, support these devices.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 return usb_id; 248 return usb_id;
249 } 249 }
250 250
251 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { 251 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
252 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); 252 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name);
253 if (!self) 253 if (!self)
254 return NULL; 254 return NULL;
255 // Test opening the device driver. This is to make sure it is available. 255 // Test opening the device driver. This is to make sure it is available.
256 // We will reopen it again in our worker thread when someone 256 // We will reopen it again in our worker thread when someone
257 // allocates the camera. 257 // allocates the camera.
258 int fd = HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY)); 258 base::ScopedFD fd(HANDLE_EINTR(open(device_name.id().c_str(), O_RDONLY)));
259 if (fd < 0) { 259 if (!fd.is_valid()) {
260 DVLOG(1) << "Cannot open device"; 260 DVLOG(1) << "Cannot open device";
261 delete self; 261 delete self;
262 return NULL; 262 return NULL;
263 } 263 }
264 close(fd);
265 264
266 return self; 265 return self;
267 } 266 }
268 267
269 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) 268 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name)
270 : state_(kIdle), 269 : state_(kIdle),
271 device_name_(device_name), 270 device_name_(device_name),
272 device_fd_(-1),
273 v4l2_thread_("V4L2Thread"), 271 v4l2_thread_("V4L2Thread"),
274 buffer_pool_(NULL), 272 buffer_pool_(NULL),
275 buffer_pool_size_(0), 273 buffer_pool_size_(0),
276 timeout_count_(0) {} 274 timeout_count_(0) {}
277 275
278 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { 276 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() {
279 state_ = kIdle; 277 state_ = kIdle;
280 // Check if the thread is running. 278 // Check if the thread is running.
281 // This means that the device have not been DeAllocated properly. 279 // This means that the device have not been DeAllocated properly.
282 DCHECK(!v4l2_thread_.IsRunning()); 280 DCHECK(!v4l2_thread_.IsRunning());
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 315
318 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, 316 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width,
319 int height, 317 int height,
320 int frame_rate, 318 int frame_rate,
321 scoped_ptr<Client> client) { 319 scoped_ptr<Client> client) {
322 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); 320 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
323 321
324 client_ = client.Pass(); 322 client_ = client.Pass();
325 323
326 // Need to open camera with O_RDWR after Linux kernel 3.3. 324 // Need to open camera with O_RDWR after Linux kernel 3.3.
327 device_fd_ = HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR)); 325 device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR)));
328 if (device_fd_ < 0) { 326 if (!device_fd_.is_valid()) {
329 SetErrorState("Failed to open V4L2 device driver."); 327 SetErrorState("Failed to open V4L2 device driver.");
330 return; 328 return;
331 } 329 }
332 device_fd_closer_.reset(&device_fd_);
333 330
334 // Test if this is a V4L2 capture device. 331 // Test if this is a V4L2 capture device.
335 v4l2_capability cap; 332 v4l2_capability cap;
336 if (!((HANDLE_EINTR(ioctl(device_fd_, VIDIOC_QUERYCAP, &cap)) == 0) && 333 if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
337 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && 334 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) &&
338 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) { 335 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) {
339 // This is not a V4L2 video capture device. 336 // This is not a V4L2 video capture device.
340 device_fd_closer_.reset(); 337 device_fd_.reset();
341 device_fd_ = -1;
342 SetErrorState("This is not a V4L2 video capture device"); 338 SetErrorState("This is not a V4L2 video capture device");
343 return; 339 return;
344 } 340 }
345 341
346 // Get supported video formats in preferred order. 342 // Get supported video formats in preferred order.
347 // For large resolutions, favour mjpeg over raw formats. 343 // For large resolutions, favour mjpeg over raw formats.
348 std::list<int> v4l2_formats; 344 std::list<int> v4l2_formats;
349 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight, 345 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight,
350 &v4l2_formats); 346 &v4l2_formats);
351 347
352 v4l2_fmtdesc fmtdesc; 348 v4l2_fmtdesc fmtdesc;
353 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); 349 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc));
354 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 350 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
355 351
356 // Enumerate image formats. 352 // Enumerate image formats.
357 std::list<int>::iterator best = v4l2_formats.end(); 353 std::list<int>::iterator best = v4l2_formats.end();
358 while (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc)) == 0) { 354 while (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) ==
355 0) {
359 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); 356 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat);
360 fmtdesc.index++; 357 fmtdesc.index++;
361 } 358 }
362 359
363 if (best == v4l2_formats.end()) { 360 if (best == v4l2_formats.end()) {
364 SetErrorState("Failed to find a supported camera format."); 361 SetErrorState("Failed to find a supported camera format.");
365 return; 362 return;
366 } 363 }
367 364
368 // Set format and frame size now. 365 // Set format and frame size now.
369 v4l2_format video_fmt; 366 v4l2_format video_fmt;
370 memset(&video_fmt, 0, sizeof(video_fmt)); 367 memset(&video_fmt, 0, sizeof(video_fmt));
371 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 368 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
372 video_fmt.fmt.pix.sizeimage = 0; 369 video_fmt.fmt.pix.sizeimage = 0;
373 video_fmt.fmt.pix.width = width; 370 video_fmt.fmt.pix.width = width;
374 video_fmt.fmt.pix.height = height; 371 video_fmt.fmt.pix.height = height;
375 video_fmt.fmt.pix.pixelformat = *best; 372 video_fmt.fmt.pix.pixelformat = *best;
376 373
377 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_S_FMT, &video_fmt)) < 0) { 374 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt)) < 0) {
378 SetErrorState("Failed to set camera format"); 375 SetErrorState("Failed to set camera format");
379 return; 376 return;
380 } 377 }
381 378
382 // Set capture framerate in the form of capture interval. 379 // Set capture framerate in the form of capture interval.
383 v4l2_streamparm streamparm; 380 v4l2_streamparm streamparm;
384 memset(&streamparm, 0, sizeof(v4l2_streamparm)); 381 memset(&streamparm, 0, sizeof(v4l2_streamparm));
385 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 382 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
386 // The following line checks that the driver knows about framerate get/set. 383 // The following line checks that the driver knows about framerate get/set.
387 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_G_PARM, &streamparm)) >= 0) { 384 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) {
388 // Now check if the device is able to accept a capture framerate set. 385 // Now check if the device is able to accept a capture framerate set.
389 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { 386 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
390 streamparm.parm.capture.timeperframe.numerator = 1; 387 streamparm.parm.capture.timeperframe.numerator = 1;
391 streamparm.parm.capture.timeperframe.denominator = 388 streamparm.parm.capture.timeperframe.denominator =
392 (frame_rate) ? frame_rate : kTypicalFramerate; 389 (frame_rate) ? frame_rate : kTypicalFramerate;
393 390
394 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_S_PARM, &streamparm)) < 0) { 391 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) <
392 0) {
395 SetErrorState("Failed to set camera framerate"); 393 SetErrorState("Failed to set camera framerate");
396 return; 394 return;
397 } 395 }
398 DVLOG(2) << "Actual camera driverframerate: " 396 DVLOG(2) << "Actual camera driverframerate: "
399 << streamparm.parm.capture.timeperframe.denominator << "/" 397 << streamparm.parm.capture.timeperframe.denominator << "/"
400 << streamparm.parm.capture.timeperframe.numerator; 398 << streamparm.parm.capture.timeperframe.numerator;
401 } 399 }
402 } 400 }
403 // TODO(mcasas): what should be done if the camera driver does not allow 401 // TODO(mcasas): what should be done if the camera driver does not allow
404 // framerate configuration, or the actual one is different from the desired? 402 // framerate configuration, or the actual one is different from the desired?
405 403
406 // Store our current width and height. 404 // Store our current width and height.
407 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width, 405 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width,
408 video_fmt.fmt.pix.height); 406 video_fmt.fmt.pix.height);
409 capture_format_.frame_rate = frame_rate; 407 capture_format_.frame_rate = frame_rate;
410 capture_format_.pixel_format = 408 capture_format_.pixel_format =
411 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat); 409 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat);
412 410
413 // Start capturing. 411 // Start capturing.
414 if (!AllocateVideoBuffers()) { 412 if (!AllocateVideoBuffers()) {
415 // Error, We can not recover. 413 // Error, We can not recover.
416 SetErrorState("Allocate buffer failed"); 414 SetErrorState("Allocate buffer failed");
417 return; 415 return;
418 } 416 }
419 417
420 // Start UVC camera. 418 // Start UVC camera.
421 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 419 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
422 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_STREAMON, &type)) == -1) { 420 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) == -1) {
423 SetErrorState("VIDIOC_STREAMON failed"); 421 SetErrorState("VIDIOC_STREAMON failed");
424 return; 422 return;
425 } 423 }
426 424
427 state_ = kCapturing; 425 state_ = kCapturing;
428 // Post task to start fetching frames from v4l2. 426 // Post task to start fetching frames from v4l2.
429 v4l2_thread_.message_loop()->PostTask( 427 v4l2_thread_.message_loop()->PostTask(
430 FROM_HERE, 428 FROM_HERE,
431 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, 429 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
432 base::Unretained(this))); 430 base::Unretained(this)));
433 } 431 }
434 432
435 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() { 433 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() {
436 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); 434 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
437 435
438 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 436 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
439 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_STREAMOFF, &type)) < 0) { 437 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) {
440 SetErrorState("VIDIOC_STREAMOFF failed"); 438 SetErrorState("VIDIOC_STREAMOFF failed");
441 return; 439 return;
442 } 440 }
443 // We don't dare to deallocate the buffers if we can't stop 441 // We don't dare to deallocate the buffers if we can't stop
444 // the capture device. 442 // the capture device.
445 DeAllocateVideoBuffers(); 443 DeAllocateVideoBuffers();
446 444
447 // We need to close and open the device if we want to change the settings 445 // We need to close and open the device if we want to change the settings
448 // Otherwise VIDIOC_S_FMT will return error 446 // Otherwise VIDIOC_S_FMT will return error
449 // Sad but true. 447 // Sad but true.
450 device_fd_closer_.reset(); 448 device_fd_.reset();
451 device_fd_ = -1;
452 state_ = kIdle; 449 state_ = kIdle;
453 client_.reset(); 450 client_.reset();
454 } 451 }
455 452
456 void VideoCaptureDeviceLinux::OnCaptureTask() { 453 void VideoCaptureDeviceLinux::OnCaptureTask() {
457 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); 454 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
458 455
459 if (state_ != kCapturing) { 456 if (state_ != kCapturing) {
460 return; 457 return;
461 } 458 }
462 459
463 fd_set r_set; 460 fd_set r_set;
464 FD_ZERO(&r_set); 461 FD_ZERO(&r_set);
465 FD_SET(device_fd_, &r_set); 462 FD_SET(device_fd_.get(), &r_set);
466 timeval timeout; 463 timeval timeout;
467 464
468 timeout.tv_sec = 0; 465 timeout.tv_sec = 0;
469 timeout.tv_usec = kCaptureTimeoutUs; 466 timeout.tv_usec = kCaptureTimeoutUs;
470 467
471 // First argument to select is the highest numbered file descriptor +1. 468 // First argument to select is the highest numbered file descriptor +1.
472 // Refer to http://linux.die.net/man/2/select for more information. 469 // Refer to http://linux.die.net/man/2/select for more information.
473 int result = 470 int result =
474 HANDLE_EINTR(select(device_fd_ + 1, &r_set, NULL, NULL, &timeout)); 471 HANDLE_EINTR(select(device_fd_.get() + 1, &r_set, NULL, NULL, &timeout));
475 // Check if select have failed. 472 // Check if select have failed.
476 if (result < 0) { 473 if (result < 0) {
477 // EINTR is a signal. This is not really an error. 474 // EINTR is a signal. This is not really an error.
478 if (errno != EINTR) { 475 if (errno != EINTR) {
479 SetErrorState("Select failed"); 476 SetErrorState("Select failed");
480 return; 477 return;
481 } 478 }
482 v4l2_thread_.message_loop()->PostDelayedTask( 479 v4l2_thread_.message_loop()->PostDelayedTask(
483 FROM_HERE, 480 FROM_HERE,
484 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, 481 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
485 base::Unretained(this)), 482 base::Unretained(this)),
486 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs)); 483 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs));
487 } 484 }
488 485
489 // Check if select timeout. 486 // Check if select timeout.
490 if (result == 0) { 487 if (result == 0) {
491 timeout_count_++; 488 timeout_count_++;
492 if (timeout_count_ >= kContinuousTimeoutLimit) { 489 if (timeout_count_ >= kContinuousTimeoutLimit) {
493 SetErrorState(base::StringPrintf( 490 SetErrorState(base::StringPrintf(
494 "Continuous timeout %d times", timeout_count_)); 491 "Continuous timeout %d times", timeout_count_));
495 timeout_count_ = 0; 492 timeout_count_ = 0;
496 return; 493 return;
497 } 494 }
498 } else { 495 } else {
499 timeout_count_ = 0; 496 timeout_count_ = 0;
500 } 497 }
501 498
502 // Check if the driver have filled a buffer. 499 // Check if the driver have filled a buffer.
503 if (FD_ISSET(device_fd_, &r_set)) { 500 if (FD_ISSET(device_fd_.get(), &r_set)) {
504 v4l2_buffer buffer; 501 v4l2_buffer buffer;
505 memset(&buffer, 0, sizeof(buffer)); 502 memset(&buffer, 0, sizeof(buffer));
506 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 503 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
507 buffer.memory = V4L2_MEMORY_MMAP; 504 buffer.memory = V4L2_MEMORY_MMAP;
508 // Dequeue a buffer. 505 // Dequeue a buffer.
509 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_DQBUF, &buffer)) == 0) { 506 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) == 0) {
510 client_->OnIncomingCapturedData( 507 client_->OnIncomingCapturedData(
511 static_cast<uint8*>(buffer_pool_[buffer.index].start), 508 static_cast<uint8*>(buffer_pool_[buffer.index].start),
512 buffer.bytesused, 509 buffer.bytesused,
513 capture_format_, 510 capture_format_,
514 0, 511 0,
515 base::TimeTicks::Now()); 512 base::TimeTicks::Now());
516 513
517 // Enqueue the buffer again. 514 // Enqueue the buffer again.
518 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_QBUF, &buffer)) == -1) { 515 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) == -1) {
519 SetErrorState(base::StringPrintf( 516 SetErrorState(base::StringPrintf(
520 "Failed to enqueue capture buffer errno %d", errno)); 517 "Failed to enqueue capture buffer errno %d", errno));
521 } 518 }
522 } else { 519 } else {
523 SetErrorState(base::StringPrintf( 520 SetErrorState(base::StringPrintf(
524 "Failed to dequeue capture buffer errno %d", errno)); 521 "Failed to dequeue capture buffer errno %d", errno));
525 return; 522 return;
526 } 523 }
527 } 524 }
528 525
529 v4l2_thread_.message_loop()->PostTask( 526 v4l2_thread_.message_loop()->PostTask(
530 FROM_HERE, 527 FROM_HERE,
531 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, 528 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
532 base::Unretained(this))); 529 base::Unretained(this)));
533 } 530 }
534 531
535 bool VideoCaptureDeviceLinux::AllocateVideoBuffers() { 532 bool VideoCaptureDeviceLinux::AllocateVideoBuffers() {
536 v4l2_requestbuffers r_buffer; 533 v4l2_requestbuffers r_buffer;
537 memset(&r_buffer, 0, sizeof(r_buffer)); 534 memset(&r_buffer, 0, sizeof(r_buffer));
538 535
539 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 536 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
540 r_buffer.memory = V4L2_MEMORY_MMAP; 537 r_buffer.memory = V4L2_MEMORY_MMAP;
541 r_buffer.count = kMaxVideoBuffers; 538 r_buffer.count = kMaxVideoBuffers;
542 539
543 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer)) < 0) { 540 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
544 return false; 541 return false;
545 } 542 }
546 543
547 if (r_buffer.count > kMaxVideoBuffers) { 544 if (r_buffer.count > kMaxVideoBuffers) {
548 r_buffer.count = kMaxVideoBuffers; 545 r_buffer.count = kMaxVideoBuffers;
549 } 546 }
550 547
551 buffer_pool_size_ = r_buffer.count; 548 buffer_pool_size_ = r_buffer.count;
552 549
553 // Map the buffers. 550 // Map the buffers.
554 buffer_pool_ = new Buffer[r_buffer.count]; 551 buffer_pool_ = new Buffer[r_buffer.count];
555 for (unsigned int i = 0; i < r_buffer.count; i++) { 552 for (unsigned int i = 0; i < r_buffer.count; i++) {
556 v4l2_buffer buffer; 553 v4l2_buffer buffer;
557 memset(&buffer, 0, sizeof(buffer)); 554 memset(&buffer, 0, sizeof(buffer));
558 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 555 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
559 buffer.memory = V4L2_MEMORY_MMAP; 556 buffer.memory = V4L2_MEMORY_MMAP;
560 buffer.index = i; 557 buffer.index = i;
561 558
562 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_QUERYBUF, &buffer)) < 0) { 559 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
563 return false; 560 return false;
564 } 561 }
565 562
566 // Some devices require mmap() to be called with both READ and WRITE. 563 // Some devices require mmap() to be called with both READ and WRITE.
567 // See crbug.com/178582. 564 // See crbug.com/178582.
568 buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, 565 buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
569 MAP_SHARED, device_fd_, buffer.m.offset); 566 MAP_SHARED, device_fd_.get(), buffer.m.offset);
570 if (buffer_pool_[i].start == MAP_FAILED) { 567 if (buffer_pool_[i].start == MAP_FAILED) {
571 return false; 568 return false;
572 } 569 }
573 buffer_pool_[i].length = buffer.length; 570 buffer_pool_[i].length = buffer.length;
574 // Enqueue the buffer in the drivers incoming queue. 571 // Enqueue the buffer in the drivers incoming queue.
575 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_QBUF, &buffer)) < 0) { 572 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
576 return false; 573 return false;
577 } 574 }
578 } 575 }
579 return true; 576 return true;
580 } 577 }
581 578
582 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() { 579 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() {
583 if (!buffer_pool_) 580 if (!buffer_pool_)
584 return; 581 return;
585 582
586 // Unmaps buffers. 583 // Unmaps buffers.
587 for (int i = 0; i < buffer_pool_size_; i++) { 584 for (int i = 0; i < buffer_pool_size_; i++) {
588 munmap(buffer_pool_[i].start, buffer_pool_[i].length); 585 munmap(buffer_pool_[i].start, buffer_pool_[i].length);
589 } 586 }
590 v4l2_requestbuffers r_buffer; 587 v4l2_requestbuffers r_buffer;
591 memset(&r_buffer, 0, sizeof(r_buffer)); 588 memset(&r_buffer, 0, sizeof(r_buffer));
592 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 589 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
593 r_buffer.memory = V4L2_MEMORY_MMAP; 590 r_buffer.memory = V4L2_MEMORY_MMAP;
594 r_buffer.count = 0; 591 r_buffer.count = 0;
595 592
596 if (HANDLE_EINTR(ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer)) < 0) { 593 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
597 SetErrorState("Failed to reset buf."); 594 SetErrorState("Failed to reset buf.");
598 } 595 }
599 596
600 delete [] buffer_pool_; 597 delete [] buffer_pool_;
601 buffer_pool_ = NULL; 598 buffer_pool_ = NULL;
602 buffer_pool_size_ = 0; 599 buffer_pool_size_ = 0;
603 } 600 }
604 601
605 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { 602 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) {
606 DCHECK(!v4l2_thread_.IsRunning() || 603 DCHECK(!v4l2_thread_.IsRunning() ||
607 v4l2_thread_.message_loop() == base::MessageLoop::current()); 604 v4l2_thread_.message_loop() == base::MessageLoop::current());
608 DVLOG(1) << reason; 605 DVLOG(1) << reason;
609 state_ = kError; 606 state_ = kError;
610 client_->OnError(reason); 607 client_->OnError(reason);
611 } 608 }
612 609
613 } // namespace media 610 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698