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

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

Issue 804473007: Linux Video Capture: small cleanup (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: corrected indentations Created 6 years 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> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <poll.h> 9 #include <poll.h>
10 #if defined(OS_OPENBSD) 10 #if defined(OS_OPENBSD)
11 #include <sys/videoio.h> 11 #include <sys/videoio.h>
12 #else 12 #else
13 #include <linux/videodev2.h> 13 #include <linux/videodev2.h>
14 #endif 14 #endif
15 #include <sys/ioctl.h> 15 #include <sys/ioctl.h>
16 #include <sys/mman.h> 16 #include <sys/mman.h>
17 17
18 #include <list> 18 #include <list>
19 #include <string> 19 #include <string>
20 20
21 #include "base/bind.h" 21 #include "base/bind.h"
22 #include "base/files/file_enumerator.h" 22 #include "base/files/file_enumerator.h"
23 #include "base/files/scoped_file.h" 23 #include "base/files/scoped_file.h"
24 #include "base/posix/eintr_wrapper.h" 24 #include "base/posix/eintr_wrapper.h"
25 #include "base/strings/stringprintf.h" 25 #include "base/strings/stringprintf.h"
26 26
27 namespace media { 27 namespace media {
28 28
29 #define GET_V4L2_FOURCC_CHAR(a, index) ((char)( ((a) >> (8 * index)) & 0xff))
30
29 // Max number of video buffers VideoCaptureDeviceLinux can allocate. 31 // Max number of video buffers VideoCaptureDeviceLinux can allocate.
30 enum { kMaxVideoBuffers = 2 }; 32 enum { kMaxVideoBuffers = 2 };
31 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw. 33 // Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw.
32 enum { kCaptureTimeoutMs = 200 }; 34 enum { kCaptureTimeoutMs = 200 };
33 // The number of continuous timeouts tolerated before treated as error. 35 // The number of continuous timeouts tolerated before treated as error.
34 enum { kContinuousTimeoutLimit = 10 }; 36 enum { kContinuousTimeoutLimit = 10 };
35 // MJPEG is preferred if the width or height is larger than this. 37 // MJPEG is preferred if the width or height is larger than this.
36 enum { kMjpegWidth = 640 }; 38 enum { kMjpegWidth = 640 };
37 enum { kMjpegHeight = 480 }; 39 enum { kMjpegHeight = 480 };
38 // Typical framerate, in fps 40 // Typical framerate, in fps
39 enum { kTypicalFramerate = 30 }; 41 enum { kTypicalFramerate = 30 };
40 42
41 // V4L2 color formats VideoCaptureDeviceLinux support. 43 // V4L2 color formats VideoCaptureDeviceLinux support.
42 static const int32 kV4l2RawFmts[] = { 44 static const int32 kV4l2RawFmts[] = {
43 V4L2_PIX_FMT_YUV420, 45 V4L2_PIX_FMT_YUV420,
44 V4L2_PIX_FMT_YUYV, 46 V4L2_PIX_FMT_YUYV,
45 V4L2_PIX_FMT_UYVY 47 V4L2_PIX_FMT_UYVY
46 }; 48 };
47 49
48 // USB VID and PID are both 4 bytes long. 50 // USB VID and PID are both 4 bytes long.
49 static const size_t kVidPidSize = 4; 51 static const size_t kVidPidSize = 4;
50 52
51 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding 53 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding
52 // USB device info directory. 54 // USB device info directory.
53 static const char kVidPathTemplate[] = 55 static const char kVidPathTemplate[] =
54 "/sys/class/video4linux/%s/device/../idVendor"; 56 "/sys/class/video4linux/%s/device/../idVendor";
55 static const char kPidPathTemplate[] = 57 static const char kPidPathTemplate[] =
56 "/sys/class/video4linux/%s/device/../idProduct"; 58 "/sys/class/video4linux/%s/device/../idProduct";
57 59
58 bool ReadIdFile(const std::string path, std::string* id) { 60 static bool ReadIdFile(const std::string path, std::string* id) {
59 char id_buf[kVidPidSize]; 61 char id_buf[kVidPidSize];
60 FILE* file = fopen(path.c_str(), "rb"); 62 FILE* file = fopen(path.c_str(), "rb");
61 if (!file) 63 if (!file)
62 return false; 64 return false;
63 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1; 65 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1;
64 fclose(file); 66 fclose(file);
65 if (!success) 67 if (!success)
66 return false; 68 return false;
67 id->append(id_buf, kVidPidSize); 69 id->append(id_buf, kVidPidSize);
68 return true; 70 return true;
69 } 71 }
70 72
71 // This function translates Video4Linux pixel formats to Chromium pixel formats, 73 // This function translates Video4Linux pixel formats to Chromium pixel formats,
72 // should only support those listed in GetListOfUsableFourCCs. 74 // should only support those listed in GetListOfUsableFourCCs.
73 // static 75 // static
74 VideoPixelFormat VideoCaptureDeviceLinux::V4l2ColorToVideoCaptureColorFormat( 76 VideoPixelFormat VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat(
75 int32 v4l2_fourcc) { 77 uint32 v4l2_fourcc) {
76 VideoPixelFormat result = PIXEL_FORMAT_UNKNOWN; 78 VideoPixelFormat result = PIXEL_FORMAT_UNKNOWN;
77 switch (v4l2_fourcc) { 79 switch (v4l2_fourcc) {
78 case V4L2_PIX_FMT_YUV420: 80 case V4L2_PIX_FMT_YUV420:
79 result = PIXEL_FORMAT_I420; 81 result = PIXEL_FORMAT_I420;
80 break; 82 break;
81 case V4L2_PIX_FMT_YUYV: 83 case V4L2_PIX_FMT_YUYV:
82 result = PIXEL_FORMAT_YUY2; 84 result = PIXEL_FORMAT_YUY2;
83 break; 85 break;
84 case V4L2_PIX_FMT_UYVY: 86 case V4L2_PIX_FMT_UYVY:
85 result = PIXEL_FORMAT_UYVY; 87 result = PIXEL_FORMAT_UYVY;
86 break; 88 break;
87 case V4L2_PIX_FMT_MJPEG: 89 case V4L2_PIX_FMT_MJPEG:
88 case V4L2_PIX_FMT_JPEG: 90 case V4L2_PIX_FMT_JPEG:
89 result = PIXEL_FORMAT_MJPEG; 91 result = PIXEL_FORMAT_MJPEG;
90 break; 92 break;
91 default: 93 default:
92 DVLOG(1) << "Unsupported pixel format " << std::hex << v4l2_fourcc; 94 DVLOG(1) << "Unsupported pixel format: "
95 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 0)
96 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 1)
97 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 2)
98 << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 3);
93 } 99 }
94 return result; 100 return result;
95 } 101 }
96 102
97 // static 103 // static
98 void VideoCaptureDeviceLinux::GetListOfUsableFourCCs(bool favour_mjpeg, 104 std::list<int> VideoCaptureDeviceLinux::GetListOfUsableFourCCs(
99 std::list<int>* fourccs) { 105 bool favour_mjpeg) {
106 std::list<int> fourccs;
100 for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i) 107 for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i)
101 fourccs->push_back(kV4l2RawFmts[i]); 108 fourccs.push_back(kV4l2RawFmts[i]);
102 if (favour_mjpeg) 109 if (favour_mjpeg)
103 fourccs->push_front(V4L2_PIX_FMT_MJPEG); 110 fourccs.push_front(V4L2_PIX_FMT_MJPEG);
104 else 111 else
105 fourccs->push_back(V4L2_PIX_FMT_MJPEG); 112 fourccs.push_back(V4L2_PIX_FMT_MJPEG);
106 113
107 // JPEG works as MJPEG on some gspca webcams from field reports. 114 // JPEG works as MJPEG on some gspca webcams from field reports.
108 // Put it as the least preferred format. 115 // Put it as the least preferred format.
109 fourccs->push_back(V4L2_PIX_FMT_JPEG); 116 fourccs.push_back(V4L2_PIX_FMT_JPEG);
117 return fourccs;
110 } 118 }
111 119
112 const std::string VideoCaptureDevice::Name::GetModel() const { 120 const std::string VideoCaptureDevice::Name::GetModel() const {
113 // |unique_id| is of the form "/dev/video2". |file_name| is "video2". 121 // |unique_id| is of the form "/dev/video2". |file_name| is "video2".
114 const std::string dev_dir = "/dev/"; 122 const std::string dev_dir = "/dev/";
115 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir)); 123 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir));
116 const std::string file_name = 124 const std::string file_name =
117 unique_id_.substr(dev_dir.length(), unique_id_.length()); 125 unique_id_.substr(dev_dir.length(), unique_id_.length());
118 126
119 const std::string vidPath = 127 const std::string vidPath =
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && 228 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) &&
221 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) { 229 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) {
222 // This is not a V4L2 video capture device. 230 // This is not a V4L2 video capture device.
223 device_fd_.reset(); 231 device_fd_.reset();
224 SetErrorState("This is not a V4L2 video capture device"); 232 SetErrorState("This is not a V4L2 video capture device");
225 return; 233 return;
226 } 234 }
227 235
228 // Get supported video formats in preferred order. 236 // Get supported video formats in preferred order.
229 // For large resolutions, favour mjpeg over raw formats. 237 // For large resolutions, favour mjpeg over raw formats.
230 std::list<int> v4l2_formats; 238 const std::list<int>& desired_v4l2_formats =
231 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight, 239 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight);
232 &v4l2_formats); 240 std::list<int>::const_iterator best = desired_v4l2_formats.end();
233 241
234 v4l2_fmtdesc fmtdesc = {0}; 242 v4l2_fmtdesc fmtdesc = {0};
235 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 243 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
236 244 for (; HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == 0;
237 // Enumerate image formats. 245 ++fmtdesc.index) {
238 std::list<int>::iterator best = v4l2_formats.end(); 246 best = std::find(desired_v4l2_formats.begin(), best, fmtdesc.pixelformat);
239 while (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) ==
240 0) {
241 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat);
242 fmtdesc.index++;
243 } 247 }
244 248 if (best == desired_v4l2_formats.end()) {
245 if (best == v4l2_formats.end()) {
246 SetErrorState("Failed to find a supported camera format."); 249 SetErrorState("Failed to find a supported camera format.");
247 return; 250 return;
248 } 251 }
249 252
250 // Set format and frame size now. 253 // Set format and frame size now.
251 v4l2_format video_fmt; 254 v4l2_format video_fmt;
252 memset(&video_fmt, 0, sizeof(v4l2_format)); 255 memset(&video_fmt, 0, sizeof(v4l2_format));
253 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 256 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
254 video_fmt.fmt.pix.sizeimage = 0; 257 video_fmt.fmt.pix.sizeimage = 0;
255 video_fmt.fmt.pix.width = width; 258 video_fmt.fmt.pix.width = width;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 V4L2_CID_POWER_LINE_FREQUENCY_50HZ : 304 V4L2_CID_POWER_LINE_FREQUENCY_50HZ :
302 V4L2_CID_POWER_LINE_FREQUENCY_60HZ; 305 V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
303 HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control)); 306 HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control));
304 } 307 }
305 308
306 // Store our current width and height. 309 // Store our current width and height.
307 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width, 310 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width,
308 video_fmt.fmt.pix.height); 311 video_fmt.fmt.pix.height);
309 capture_format_.frame_rate = frame_rate; 312 capture_format_.frame_rate = frame_rate;
310 capture_format_.pixel_format = 313 capture_format_.pixel_format =
311 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat); 314 V4l2FourCcToChromiumPixelFormat(video_fmt.fmt.pix.pixelformat);
312 315
313 // Start capturing.
314 if (!AllocateVideoBuffers()) { 316 if (!AllocateVideoBuffers()) {
315 // Error, We can not recover. 317 SetErrorState("Allocate buffers failed");
316 SetErrorState("Allocate buffer failed");
317 return; 318 return;
318 } 319 }
319 320
320 // Start UVC camera. 321 // Start UVC camera.
321 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 322 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
322 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) == -1) { 323 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) == -1) {
323 SetErrorState("VIDIOC_STREAMON failed"); 324 SetErrorState("VIDIOC_STREAMON failed");
324 return; 325 return;
325 } 326 }
326 327
327 is_capturing_ = true; 328 is_capturing_ = true;
328 // Post task to start fetching frames from v4l2. 329 // Post task to start fetching frames from v4l2.
329 v4l2_thread_.message_loop()->PostTask( 330 v4l2_thread_.message_loop()->PostTask(
330 FROM_HERE, 331 FROM_HERE,
331 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, 332 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask,
332 base::Unretained(this))); 333 base::Unretained(this)));
333 } 334 }
334 335
335 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() { 336 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() {
336 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); 337 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
337 338
338 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 339 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
339 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) { 340 if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) {
340 SetErrorState("VIDIOC_STREAMOFF failed"); 341 SetErrorState("VIDIOC_STREAMOFF failed");
341 return; 342 return;
342 } 343 }
343 // We don't dare to deallocate the buffers if we can't stop 344 // We don't dare to deallocate the buffers if we can't stop the capture
344 // the capture device. 345 // device.
345 DeAllocateVideoBuffers(); 346 DeAllocateVideoBuffers();
346 347
347 // We need to close and open the device if we want to change the settings 348 // We need to close and open the device if we want to change the settings.
348 // Otherwise VIDIOC_S_FMT will return error 349 // Otherwise VIDIOC_S_FMT will return error. Sad but true.
349 // Sad but true.
350 device_fd_.reset(); 350 device_fd_.reset();
351 is_capturing_ = false; 351 is_capturing_ = false;
352 client_.reset(); 352 client_.reset();
353 } 353 }
354 354
355 void VideoCaptureDeviceLinux::OnCaptureTask() { 355 void VideoCaptureDeviceLinux::OnCaptureTask() {
356 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); 356 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current());
357 if (!is_capturing_) 357 if (!is_capturing_)
358 return; 358 return;
359 359
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
484 } 484 }
485 485
486 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { 486 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) {
487 DCHECK(!v4l2_thread_.IsRunning() || 487 DCHECK(!v4l2_thread_.IsRunning() ||
488 v4l2_thread_.message_loop() == base::MessageLoop::current()); 488 v4l2_thread_.message_loop() == base::MessageLoop::current());
489 is_capturing_ = false; 489 is_capturing_ = false;
490 client_->OnError(reason); 490 client_->OnError(reason);
491 } 491 }
492 492
493 } // namespace media 493 } // namespace media
OLDNEW
« no previous file with comments | « media/video/capture/linux/video_capture_device_linux.h ('k') | media/video/capture/video_capture_types.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698