blob: 30865235b6be8a468a8e10f43b196f6e4638ab75 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mallinath@webrtc.org12984f02012-02-16 18:18:21 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/video_capture/linux/video_capture_linux.h"
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +020012
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000013#include <errno.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <fcntl.h>
15#include <linux/videodev2.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000016#include <stdio.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000017#include <string.h>
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000018#include <sys/ioctl.h>
19#include <sys/mman.h>
Yves Gerey3e707812018-11-28 16:47:49 +010020#include <sys/select.h>
21#include <time.h>
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000022#include <unistd.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020023
niklase@google.com470e71d2011-07-07 08:21:25 +000024#include <new>
Yves Gerey3e707812018-11-28 16:47:49 +010025#include <string>
niklase@google.com470e71d2011-07-07 08:21:25 +000026
Mirko Bonadeid9708072019-01-25 20:26:48 +010027#include "api/scoped_refptr.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "media/base/video_common.h"
Yves Gerey3e707812018-11-28 16:47:49 +010029#include "modules/video_capture/video_capture.h"
Mirko Bonadei72c42502017-11-09 09:33:23 +010030#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080031#include "rtc_base/ref_counted_object.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000032
Peter Boström1d194412016-03-21 16:44:31 +010033namespace webrtc {
34namespace videocapturemodule {
35rtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create(
Peter Boström1d194412016-03-21 16:44:31 +010036 const char* deviceUniqueId) {
Mirko Bonadei72c42502017-11-09 09:33:23 +010037 rtc::scoped_refptr<VideoCaptureModuleV4L2> implementation(
38 new rtc::RefCountedObject<VideoCaptureModuleV4L2>());
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000039
Mirko Bonadei72c42502017-11-09 09:33:23 +010040 if (implementation->Init(deviceUniqueId) != 0)
41 return nullptr;
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000042
Mirko Bonadei72c42502017-11-09 09:33:23 +010043 return implementation;
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000044}
45
nisseb29b9c82016-12-12 00:22:56 -080046VideoCaptureModuleV4L2::VideoCaptureModuleV4L2()
47 : VideoCaptureImpl(),
tommi@webrtc.org875c97e2015-02-04 11:11:53 +000048 _deviceId(-1),
mallinath@webrtc.org0d757b82012-02-21 16:47:55 +000049 _deviceFd(-1),
50 _buffersAllocatedByDevice(-1),
tommi@webrtc.org875c97e2015-02-04 11:11:53 +000051 _currentWidth(-1),
mallinath@webrtc.org0d757b82012-02-21 16:47:55 +000052 _currentHeight(-1),
tommi@webrtc.org875c97e2015-02-04 11:11:53 +000053 _currentFrameRate(-1),
mallinath@webrtc.org0d757b82012-02-21 16:47:55 +000054 _captureStarted(false),
nisseeb44b392017-04-28 07:18:05 -070055 _captureVideoType(VideoType::kI420),
56 _pool(NULL) {}
niklase@google.com470e71d2011-07-07 08:21:25 +000057
Mirko Bonadei72c42502017-11-09 09:33:23 +010058int32_t VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8) {
59 int len = strlen((const char*)deviceUniqueIdUTF8);
60 _deviceUniqueId = new (std::nothrow) char[len + 1];
61 if (_deviceUniqueId) {
62 memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1);
63 }
niklase@google.com470e71d2011-07-07 08:21:25 +000064
Mirko Bonadei72c42502017-11-09 09:33:23 +010065 int fd;
66 char device[32];
67 bool found = false;
niklase@google.com470e71d2011-07-07 08:21:25 +000068
Mirko Bonadei72c42502017-11-09 09:33:23 +010069 /* detect /dev/video [0-63] entries */
70 int n;
71 for (n = 0; n < 64; n++) {
72 sprintf(device, "/dev/video%d", n);
73 if ((fd = open(device, O_RDONLY)) != -1) {
74 // query device capabilities
75 struct v4l2_capability cap;
76 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
77 if (cap.bus_info[0] != 0) {
78 if (strncmp((const char*)cap.bus_info,
79 (const char*)deviceUniqueIdUTF8,
80 strlen((const char*)deviceUniqueIdUTF8)) ==
81 0) // match with device id
82 {
83 close(fd);
84 found = true;
85 break; // fd matches with device unique id supplied
86 }
niklase@google.com470e71d2011-07-07 08:21:25 +000087 }
Mirko Bonadei72c42502017-11-09 09:33:23 +010088 }
89 close(fd); // close since this is not the matching device
niklase@google.com470e71d2011-07-07 08:21:25 +000090 }
Mirko Bonadei72c42502017-11-09 09:33:23 +010091 }
92 if (!found) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010093 RTC_LOG(LS_INFO) << "no matching device found";
Mirko Bonadei72c42502017-11-09 09:33:23 +010094 return -1;
95 }
96 _deviceId = n; // store the device id
97 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000098}
99
Mirko Bonadei72c42502017-11-09 09:33:23 +0100100VideoCaptureModuleV4L2::~VideoCaptureModuleV4L2() {
101 StopCapture();
102 if (_deviceFd != -1)
103 close(_deviceFd);
niklase@google.com470e71d2011-07-07 08:21:25 +0000104}
105
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000106int32_t VideoCaptureModuleV4L2::StartCapture(
Mirko Bonadei72c42502017-11-09 09:33:23 +0100107 const VideoCaptureCapability& capability) {
108 if (_captureStarted) {
109 if (capability.width == _currentWidth &&
110 capability.height == _currentHeight &&
111 _captureVideoType == capability.videoType) {
112 return 0;
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000113 } else {
Mirko Bonadei72c42502017-11-09 09:33:23 +0100114 StopCapture();
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000115 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100116 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000117
Mirko Bonadei72c42502017-11-09 09:33:23 +0100118 rtc::CritScope cs(&_captureCritSect);
119 // first open /dev/video device
120 char device[20];
121 sprintf(device, "/dev/video%d", (int)_deviceId);
122
123 if ((_deviceFd = open(device, O_RDWR | O_NONBLOCK, 0)) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100124 RTC_LOG(LS_INFO) << "error in opening " << device << " errono = " << errno;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100125 return -1;
126 }
127
128 // Supported video formats in preferred order.
129 // If the requested resolution is larger than VGA, we prefer MJPEG. Go for
130 // I420 otherwise.
131 const int nFormats = 5;
132 unsigned int fmts[nFormats];
133 if (capability.width > 640 || capability.height > 480) {
134 fmts[0] = V4L2_PIX_FMT_MJPEG;
135 fmts[1] = V4L2_PIX_FMT_YUV420;
136 fmts[2] = V4L2_PIX_FMT_YUYV;
137 fmts[3] = V4L2_PIX_FMT_UYVY;
138 fmts[4] = V4L2_PIX_FMT_JPEG;
139 } else {
140 fmts[0] = V4L2_PIX_FMT_YUV420;
141 fmts[1] = V4L2_PIX_FMT_YUYV;
142 fmts[2] = V4L2_PIX_FMT_UYVY;
143 fmts[3] = V4L2_PIX_FMT_MJPEG;
144 fmts[4] = V4L2_PIX_FMT_JPEG;
145 }
146
147 // Enumerate image formats.
148 struct v4l2_fmtdesc fmt;
149 int fmtsIdx = nFormats;
150 memset(&fmt, 0, sizeof(fmt));
151 fmt.index = 0;
152 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100153 RTC_LOG(LS_INFO) << "Video Capture enumerats supported image formats:";
Mirko Bonadei72c42502017-11-09 09:33:23 +0100154 while (ioctl(_deviceFd, VIDIOC_ENUM_FMT, &fmt) == 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100155 RTC_LOG(LS_INFO) << " { pixelformat = "
156 << cricket::GetFourccName(fmt.pixelformat)
157 << ", description = '" << fmt.description << "' }";
Mirko Bonadei72c42502017-11-09 09:33:23 +0100158 // Match the preferred order.
159 for (int i = 0; i < nFormats; i++) {
160 if (fmt.pixelformat == fmts[i] && i < fmtsIdx)
161 fmtsIdx = i;
braveyao@webrtc.org254d85a2013-02-04 07:53:53 +0000162 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100163 // Keep enumerating.
164 fmt.index++;
165 }
braveyao@webrtc.org254d85a2013-02-04 07:53:53 +0000166
Mirko Bonadei72c42502017-11-09 09:33:23 +0100167 if (fmtsIdx == nFormats) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100168 RTC_LOG(LS_INFO) << "no supporting video formats found";
Mirko Bonadei72c42502017-11-09 09:33:23 +0100169 return -1;
170 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100171 RTC_LOG(LS_INFO) << "We prefer format "
172 << cricket::GetFourccName(fmts[fmtsIdx]);
Mirko Bonadei72c42502017-11-09 09:33:23 +0100173 }
braveyao@webrtc.org254d85a2013-02-04 07:53:53 +0000174
Mirko Bonadei72c42502017-11-09 09:33:23 +0100175 struct v4l2_format video_fmt;
176 memset(&video_fmt, 0, sizeof(struct v4l2_format));
177 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
178 video_fmt.fmt.pix.sizeimage = 0;
179 video_fmt.fmt.pix.width = capability.width;
180 video_fmt.fmt.pix.height = capability.height;
181 video_fmt.fmt.pix.pixelformat = fmts[fmtsIdx];
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000182
Mirko Bonadei72c42502017-11-09 09:33:23 +0100183 if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
184 _captureVideoType = VideoType::kYUY2;
185 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
186 _captureVideoType = VideoType::kI420;
187 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
188 _captureVideoType = VideoType::kUYVY;
189 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG ||
190 video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
191 _captureVideoType = VideoType::kMJPEG;
niklase@google.com470e71d2011-07-07 08:21:25 +0000192
Mirko Bonadei72c42502017-11-09 09:33:23 +0100193 // set format and frame size now
194 if (ioctl(_deviceFd, VIDIOC_S_FMT, &video_fmt) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100195 RTC_LOG(LS_INFO) << "error in VIDIOC_S_FMT, errno = " << errno;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100196 return -1;
197 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
Mirko Bonadei72c42502017-11-09 09:33:23 +0100199 // initialize current width and height
200 _currentWidth = video_fmt.fmt.pix.width;
201 _currentHeight = video_fmt.fmt.pix.height;
mallinath@webrtc.org42033b42012-08-01 06:31:34 +0000202
Mirko Bonadei72c42502017-11-09 09:33:23 +0100203 // Trying to set frame rate, before check driver capability.
204 bool driver_framerate_support = true;
205 struct v4l2_streamparm streamparms;
206 memset(&streamparms, 0, sizeof(streamparms));
207 streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
208 if (ioctl(_deviceFd, VIDIOC_G_PARM, &streamparms) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100209 RTC_LOG(LS_INFO) << "error in VIDIOC_G_PARM errno = " << errno;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100210 driver_framerate_support = false;
211 // continue
212 } else {
213 // check the capability flag is set to V4L2_CAP_TIMEPERFRAME.
214 if (streamparms.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
215 // driver supports the feature. Set required framerate.
216 memset(&streamparms, 0, sizeof(streamparms));
217 streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
218 streamparms.parm.capture.timeperframe.numerator = 1;
219 streamparms.parm.capture.timeperframe.denominator = capability.maxFPS;
220 if (ioctl(_deviceFd, VIDIOC_S_PARM, &streamparms) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100221 RTC_LOG(LS_INFO) << "Failed to set the framerate. errno=" << errno;
mallinath@webrtc.org42033b42012-08-01 06:31:34 +0000222 driver_framerate_support = false;
mallinath@webrtc.org42033b42012-08-01 06:31:34 +0000223 } else {
Mirko Bonadei72c42502017-11-09 09:33:23 +0100224 _currentFrameRate = capability.maxFPS;
mallinath@webrtc.org42033b42012-08-01 06:31:34 +0000225 }
226 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100227 }
228 // If driver doesn't support framerate control, need to hardcode.
229 // Hardcoding the value based on the frame size.
230 if (!driver_framerate_support) {
231 if (_currentWidth >= 800 && _captureVideoType != VideoType::kMJPEG) {
232 _currentFrameRate = 15;
233 } else {
234 _currentFrameRate = 30;
niklase@google.com470e71d2011-07-07 08:21:25 +0000235 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100236 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000237
Mirko Bonadei72c42502017-11-09 09:33:23 +0100238 if (!AllocateVideoBuffers()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100239 RTC_LOG(LS_INFO) << "failed to allocate video capture buffers";
Mirko Bonadei72c42502017-11-09 09:33:23 +0100240 return -1;
241 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000242
Mirko Bonadei72c42502017-11-09 09:33:23 +0100243 // start capture thread;
244 if (!_captureThread) {
Niels Möller4731f002019-05-03 09:34:24 +0200245 quit_ = false;
246 _captureThread.reset(
247 new rtc::PlatformThread(VideoCaptureModuleV4L2::CaptureThread, this,
248 "CaptureThread", rtc::kHighPriority));
Mirko Bonadei72c42502017-11-09 09:33:23 +0100249 _captureThread->Start();
Mirko Bonadei72c42502017-11-09 09:33:23 +0100250 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000251
Mirko Bonadei72c42502017-11-09 09:33:23 +0100252 // Needed to start UVC camera - from the uvcview application
253 enum v4l2_buf_type type;
254 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
255 if (ioctl(_deviceFd, VIDIOC_STREAMON, &type) == -1) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100256 RTC_LOG(LS_INFO) << "Failed to turn on stream";
Mirko Bonadei72c42502017-11-09 09:33:23 +0100257 return -1;
258 }
259
260 _captureStarted = true;
261 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000262}
263
Mirko Bonadei72c42502017-11-09 09:33:23 +0100264int32_t VideoCaptureModuleV4L2::StopCapture() {
265 if (_captureThread) {
Niels Möller4731f002019-05-03 09:34:24 +0200266 {
267 rtc::CritScope cs(&_captureCritSect);
268 quit_ = true;
269 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100270 // Make sure the capture thread stop stop using the critsect.
271 _captureThread->Stop();
272 _captureThread.reset();
273 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000274
Mirko Bonadei72c42502017-11-09 09:33:23 +0100275 rtc::CritScope cs(&_captureCritSect);
276 if (_captureStarted) {
277 _captureStarted = false;
perkj@webrtc.orgc2fde802012-08-08 14:01:09 +0000278
Mirko Bonadei72c42502017-11-09 09:33:23 +0100279 DeAllocateVideoBuffers();
280 close(_deviceFd);
281 _deviceFd = -1;
282 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000283
Mirko Bonadei72c42502017-11-09 09:33:23 +0100284 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000285}
286
Mirko Bonadei72c42502017-11-09 09:33:23 +0100287// critical section protected by the caller
niklase@google.com470e71d2011-07-07 08:21:25 +0000288
Mirko Bonadei72c42502017-11-09 09:33:23 +0100289bool VideoCaptureModuleV4L2::AllocateVideoBuffers() {
290 struct v4l2_requestbuffers rbuffer;
291 memset(&rbuffer, 0, sizeof(v4l2_requestbuffers));
niklase@google.com470e71d2011-07-07 08:21:25 +0000292
Mirko Bonadei72c42502017-11-09 09:33:23 +0100293 rbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
294 rbuffer.memory = V4L2_MEMORY_MMAP;
295 rbuffer.count = kNoOfV4L2Bufffers;
296
297 if (ioctl(_deviceFd, VIDIOC_REQBUFS, &rbuffer) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100298 RTC_LOG(LS_INFO) << "Could not get buffers from device. errno = " << errno;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100299 return false;
300 }
301
302 if (rbuffer.count > kNoOfV4L2Bufffers)
niklase@google.com470e71d2011-07-07 08:21:25 +0000303 rbuffer.count = kNoOfV4L2Bufffers;
304
Mirko Bonadei72c42502017-11-09 09:33:23 +0100305 _buffersAllocatedByDevice = rbuffer.count;
306
307 // Map the buffers
308 _pool = new Buffer[rbuffer.count];
309
310 for (unsigned int i = 0; i < rbuffer.count; i++) {
311 struct v4l2_buffer buffer;
312 memset(&buffer, 0, sizeof(v4l2_buffer));
313 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
314 buffer.memory = V4L2_MEMORY_MMAP;
315 buffer.index = i;
316
317 if (ioctl(_deviceFd, VIDIOC_QUERYBUF, &buffer) < 0) {
318 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000319 }
320
Mirko Bonadei72c42502017-11-09 09:33:23 +0100321 _pool[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
322 MAP_SHARED, _deviceFd, buffer.m.offset);
niklase@google.com470e71d2011-07-07 08:21:25 +0000323
Mirko Bonadei72c42502017-11-09 09:33:23 +0100324 if (MAP_FAILED == _pool[i].start) {
325 for (unsigned int j = 0; j < i; j++)
326 munmap(_pool[j].start, _pool[j].length);
327 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100329
330 _pool[i].length = buffer.length;
331
332 if (ioctl(_deviceFd, VIDIOC_QBUF, &buffer) < 0) {
333 return false;
334 }
335 }
336 return true;
337}
338
339bool VideoCaptureModuleV4L2::DeAllocateVideoBuffers() {
340 // unmap buffers
341 for (int i = 0; i < _buffersAllocatedByDevice; i++)
342 munmap(_pool[i].start, _pool[i].length);
343
344 delete[] _pool;
345
346 // turn off stream
347 enum v4l2_buf_type type;
348 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
349 if (ioctl(_deviceFd, VIDIOC_STREAMOFF, &type) < 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100350 RTC_LOG(LS_INFO) << "VIDIOC_STREAMOFF error. errno: " << errno;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100351 }
352
353 return true;
354}
355
356bool VideoCaptureModuleV4L2::CaptureStarted() {
357 return _captureStarted;
358}
359
Niels Möller4731f002019-05-03 09:34:24 +0200360void VideoCaptureModuleV4L2::CaptureThread(void* obj) {
361 VideoCaptureModuleV4L2* capture = static_cast<VideoCaptureModuleV4L2*>(obj);
362 while (capture->CaptureProcess()) {
363 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100364}
365bool VideoCaptureModuleV4L2::CaptureProcess() {
366 int retVal = 0;
367 fd_set rSet;
368 struct timeval timeout;
369
Mirko Bonadei72c42502017-11-09 09:33:23 +0100370 FD_ZERO(&rSet);
371 FD_SET(_deviceFd, &rSet);
372 timeout.tv_sec = 1;
373 timeout.tv_usec = 0;
374
Niels Möller4731f002019-05-03 09:34:24 +0200375 // _deviceFd written only in StartCapture, when this thread isn't running.
Mirko Bonadei72c42502017-11-09 09:33:23 +0100376 retVal = select(_deviceFd + 1, &rSet, NULL, NULL, &timeout);
377 if (retVal < 0 && errno != EINTR) // continue if interrupted
378 {
379 // select failed
380 return false;
381 } else if (retVal == 0) {
382 // select timed out
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 return true;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100384 } else if (!FD_ISSET(_deviceFd, &rSet)) {
385 // not event on camera handle
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 return true;
Mirko Bonadei72c42502017-11-09 09:33:23 +0100387 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000388
Niels Möller4731f002019-05-03 09:34:24 +0200389 {
390 rtc::CritScope cs(&_captureCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000391
Niels Möller4731f002019-05-03 09:34:24 +0200392 if (quit_) {
393 return false;
394 }
395
396 if (_captureStarted) {
397 struct v4l2_buffer buf;
398 memset(&buf, 0, sizeof(struct v4l2_buffer));
399 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
400 buf.memory = V4L2_MEMORY_MMAP;
401 // dequeue a buffer - repeat until dequeued properly!
402 while (ioctl(_deviceFd, VIDIOC_DQBUF, &buf) < 0) {
403 if (errno != EINTR) {
404 RTC_LOG(LS_INFO) << "could not sync on a buffer on device "
405 << strerror(errno);
406 return true;
407 }
408 }
409 VideoCaptureCapability frameInfo;
410 frameInfo.width = _currentWidth;
411 frameInfo.height = _currentHeight;
412 frameInfo.videoType = _captureVideoType;
413
414 // convert to to I420 if needed
415 IncomingFrame((unsigned char*)_pool[buf.index].start, buf.bytesused,
416 frameInfo);
417 // enqueue the buffer again
418 if (ioctl(_deviceFd, VIDIOC_QBUF, &buf) == -1) {
419 RTC_LOG(LS_INFO) << "Failed to enqueue capture buffer";
420 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 }
Mirko Bonadei72c42502017-11-09 09:33:23 +0100422 }
423 usleep(0);
424 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000425}
426
Mirko Bonadei72c42502017-11-09 09:33:23 +0100427int32_t VideoCaptureModuleV4L2::CaptureSettings(
428 VideoCaptureCapability& settings) {
429 settings.width = _currentWidth;
430 settings.height = _currentHeight;
431 settings.maxFPS = _currentFrameRate;
432 settings.videoType = _captureVideoType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000433
Mirko Bonadei72c42502017-11-09 09:33:23 +0100434 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000435}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000436} // namespace videocapturemodule
437} // namespace webrtc