1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/capture/video/linux/fake_v4l2_impl.h"
6
7 #include <string.h>
8 #include <sys/mman.h>
9 #include <sys/time.h>
10 #include <unistd.h>
11 #include <queue>
12
13 #include "base/bind.h"
14 #include "base/bits.h"
15 #include "base/stl_util.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/threading/thread.h"
18 #include "media/base/video_frame.h"
19
20 #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
21
22 namespace media {
23
24 static const int kInvalidId = -1;
25 static const int kSuccessReturnValue = 0;
26 static const int kErrorReturnValue = -1;
27 static const uint32_t kMaxBufferCount = 5;
28 static const int kDefaultWidth = 640;
29 static const int kDefaultHeight = 480;
30
31 // 20 fps.
32 static const int kDefaultFrameInternvalNumerator = 50;
33 static const int kDefaultFrameInternvalDenominator = 1000;
34
RoundUpToMultipleOfPageSize(__u32 size)35 __u32 RoundUpToMultipleOfPageSize(__u32 size) {
36 CHECK(base::bits::IsPowerOfTwo(getpagesize()));
37 return base::bits::Align(size, getpagesize());
38 }
39
40 struct FakeV4L2Buffer {
FakeV4L2Buffermedia::FakeV4L2Buffer41 FakeV4L2Buffer(__u32 index, __u32 offset, __u32 length)
42 : index(index),
43 offset(offset),
44 length(length),
45 flags(V4L2_BUF_FLAG_MAPPED),
46 sequence(0) {}
47
48 const __u32 index;
49 const __u32 offset;
50 const __u32 length;
51 __u32 flags;
52 timeval timestamp;
53 __u32 sequence;
54 std::unique_ptr<uint8_t[]> data;
55 };
56
57 class FakeV4L2Impl::OpenedDevice {
58 public:
OpenedDevice(const FakeV4L2DeviceConfig & config,int open_flags)59 explicit OpenedDevice(const FakeV4L2DeviceConfig& config, int open_flags)
60 : config_(config),
61 open_flags_(open_flags),
62 wait_for_outgoing_queue_event_(
63 base::WaitableEvent::ResetPolicy::AUTOMATIC),
64 frame_production_thread_("FakeV4L2Impl FakeProductionThread") {
65 selected_format_.width = kDefaultWidth;
66 selected_format_.height = kDefaultHeight;
67 selected_format_.pixelformat = V4L2_PIX_FMT_YUV420;
68 selected_format_.field = V4L2_FIELD_NONE;
69 selected_format_.bytesperline = kDefaultWidth;
70 selected_format_.sizeimage = VideoFrame::AllocationSize(
71 PIXEL_FORMAT_I420, gfx::Size(kDefaultWidth, kDefaultHeight));
72 selected_format_.colorspace = V4L2_COLORSPACE_REC709;
73 selected_format_.priv = 0;
74
75 timeperframe_.numerator = kDefaultFrameInternvalNumerator;
76 timeperframe_.denominator = kDefaultFrameInternvalDenominator;
77 }
78
device_id() const79 const std::string& device_id() const { return config_.descriptor.device_id; }
80
open_flags() const81 int open_flags() const { return open_flags_; }
82
LookupBufferFromOffset(off_t offset)83 FakeV4L2Buffer* LookupBufferFromOffset(off_t offset) {
84 auto buffer_iter =
85 std::find_if(device_buffers_.begin(), device_buffers_.end(),
86 [offset](const FakeV4L2Buffer& buffer) {
87 return buffer.offset == offset;
88 });
89 if (buffer_iter == device_buffers_.end())
90 return nullptr;
91 return &(*buffer_iter);
92 }
93
BlockUntilOutputQueueHasBuffer(int timeout_in_milliseconds)94 bool BlockUntilOutputQueueHasBuffer(int timeout_in_milliseconds) {
95 {
96 base::AutoLock lock(outgoing_queue_lock_);
97 if (!outgoing_queue_.empty()) {
98 return true;
99 }
100 }
101 return wait_for_outgoing_queue_event_.TimedWait(
102 base::TimeDelta::FromMilliseconds(timeout_in_milliseconds));
103 }
104
enum_fmt(v4l2_fmtdesc * fmtdesc)105 int enum_fmt(v4l2_fmtdesc* fmtdesc) {
106 if (fmtdesc->index > 0u) {
107 // We only support a single format for now.
108 return EINVAL;
109 }
110 if (fmtdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
111 // We only support video capture.
112 return EINVAL;
113 }
114 fmtdesc->flags = 0u;
115 strcpy(reinterpret_cast<char*>(fmtdesc->description), "YUV420");
116 fmtdesc->pixelformat = V4L2_PIX_FMT_YUV420;
117 memset(fmtdesc->reserved, 0, sizeof(fmtdesc->reserved));
118 return kSuccessReturnValue;
119 }
120
querycap(v4l2_capability * cap)121 int querycap(v4l2_capability* cap) {
122 strcpy(reinterpret_cast<char*>(cap->driver), "FakeV4L2");
123 CHECK(config_.descriptor.display_name().size() < 31);
124 strcpy(reinterpret_cast<char*>(cap->driver),
125 config_.descriptor.display_name().c_str());
126 cap->bus_info[0] = 0;
127 // Provide arbitrary version info
128 cap->version = KERNEL_VERSION(1, 0, 0);
129 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE;
130 memset(cap->reserved, 0, sizeof(cap->reserved));
131 return kSuccessReturnValue;
132 }
133
s_ctrl(v4l2_control * control)134 int s_ctrl(v4l2_control* control) { return kSuccessReturnValue; }
135
s_ext_ctrls(v4l2_ext_controls * control)136 int s_ext_ctrls(v4l2_ext_controls* control) { return kSuccessReturnValue; }
137
queryctrl(v4l2_queryctrl * control)138 int queryctrl(v4l2_queryctrl* control) {
139 switch (control->id) {
140 case V4L2_CID_PAN_ABSOLUTE:
141 if (!config_.descriptor.control_support().pan)
142 return EINVAL;
143 break;
144 case V4L2_CID_TILT_ABSOLUTE:
145 if (!config_.descriptor.control_support().tilt)
146 return EINVAL;
147 break;
148 case V4L2_CID_ZOOM_ABSOLUTE:
149 if (!config_.descriptor.control_support().zoom)
150 return EINVAL;
151 break;
152 default:
153 return EINVAL;
154 }
155 control->flags = 0;
156 control->minimum = 100;
157 control->maximum = 400;
158 control->step = 1;
159 return 0;
160 }
161
s_fmt(v4l2_format * format)162 int s_fmt(v4l2_format* format) {
163 if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
164 return EINVAL;
165 v4l2_pix_format& pix_format = format->fmt.pix;
166 // We only support YUV420 output for now. Tell this to the client by
167 // overwriting whatever format it requested.
168 pix_format.pixelformat = V4L2_PIX_FMT_YUV420;
169 // We only support non-interlaced output
170 pix_format.field = V4L2_FIELD_NONE;
171 // We do not support padding bytes
172 pix_format.bytesperline = pix_format.width;
173 pix_format.sizeimage = VideoFrame::AllocationSize(
174 PIXEL_FORMAT_I420, gfx::Size(pix_format.width, pix_format.height));
175 // Arbitrary colorspace
176 pix_format.colorspace = V4L2_COLORSPACE_REC709;
177 pix_format.priv = 0;
178 selected_format_ = pix_format;
179 return kSuccessReturnValue;
180 }
181
g_parm(v4l2_streamparm * parm)182 int g_parm(v4l2_streamparm* parm) {
183 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
184 return EINVAL;
185 v4l2_captureparm& captureparm = parm->parm.capture;
186 captureparm.capability = V4L2_CAP_TIMEPERFRAME;
187 captureparm.timeperframe = timeperframe_;
188 captureparm.extendedmode = 0;
189 captureparm.readbuffers = 3; // arbitrary choice
190 memset(captureparm.reserved, 0, sizeof(captureparm.reserved));
191 return kSuccessReturnValue;
192 }
193
s_parm(v4l2_streamparm * parm)194 int s_parm(v4l2_streamparm* parm) {
195 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
196 return EINVAL;
197 v4l2_captureparm& captureparm = parm->parm.capture;
198 captureparm.capability = V4L2_CAP_TIMEPERFRAME;
199 timeperframe_ = captureparm.timeperframe;
200 captureparm.extendedmode = 0;
201 captureparm.readbuffers = 3; // arbitrary choice
202 memset(captureparm.reserved, 0, sizeof(captureparm.reserved));
203 return kSuccessReturnValue;
204 }
205
reqbufs(v4l2_requestbuffers * bufs)206 int reqbufs(v4l2_requestbuffers* bufs) {
207 if (bufs->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
208 return EINVAL;
209 if (bufs->memory != V4L2_MEMORY_MMAP) {
210 // We only support device-owned buffers
211 return EINVAL;
212 }
213 incoming_queue_ = std::queue<FakeV4L2Buffer*>();
214 outgoing_queue_ = std::queue<FakeV4L2Buffer*>();
215 device_buffers_.clear();
216 uint32_t target_buffer_count = std::min(bufs->count, kMaxBufferCount);
217 bufs->count = target_buffer_count;
218 __u32 current_offset = 0;
219 for (uint32_t i = 0; i < target_buffer_count; i++) {
220 device_buffers_.emplace_back(i, current_offset,
221 selected_format_.sizeimage);
222 current_offset += RoundUpToMultipleOfPageSize(selected_format_.sizeimage);
223 }
224 memset(bufs->reserved, 0, sizeof(bufs->reserved));
225 return kSuccessReturnValue;
226 }
227
querybuf(v4l2_buffer * buf)228 int querybuf(v4l2_buffer* buf) {
229 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
230 return EINVAL;
231 if (buf->index >= device_buffers_.size())
232 return EINVAL;
233 auto& buffer = device_buffers_[buf->index];
234 buf->memory = V4L2_MEMORY_MMAP;
235 buf->flags = buffer.flags;
236 buf->m.offset = buffer.offset;
237 buf->length = buffer.length;
238 return kSuccessReturnValue;
239 }
240
qbuf(v4l2_buffer * buf)241 int qbuf(v4l2_buffer* buf) {
242 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
243 return EINVAL;
244 if (buf->memory != V4L2_MEMORY_MMAP)
245 return EINVAL;
246 if (buf->index >= device_buffers_.size())
247 return EINVAL;
248 auto& buffer = device_buffers_[buf->index];
249 buffer.flags = V4L2_BUF_FLAG_MAPPED & V4L2_BUF_FLAG_QUEUED;
250 buf->flags = buffer.flags;
251
252 base::AutoLock lock(incoming_queue_lock_);
253 incoming_queue_.push(&buffer);
254 return kSuccessReturnValue;
255 }
256
dqbuf(v4l2_buffer * buf)257 int dqbuf(v4l2_buffer* buf) {
258 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
259 return EINVAL;
260 if (buf->memory != V4L2_MEMORY_MMAP)
261 return EINVAL;
262 bool outgoing_queue_is_empty = true;
263 {
264 base::AutoLock lock(outgoing_queue_lock_);
265 outgoing_queue_is_empty = outgoing_queue_.empty();
266 }
267 if (outgoing_queue_is_empty) {
268 if (open_flags_ & O_NONBLOCK)
269 return EAGAIN;
270 wait_for_outgoing_queue_event_.Wait();
271 }
272 base::AutoLock lock(outgoing_queue_lock_);
273 auto* buffer = outgoing_queue_.front();
274 outgoing_queue_.pop();
275 buffer->flags = V4L2_BUF_FLAG_MAPPED & V4L2_BUF_FLAG_DONE;
276 buf->index = buffer->index;
277 buf->bytesused = VideoFrame::AllocationSize(
278 PIXEL_FORMAT_I420,
279 gfx::Size(selected_format_.width, selected_format_.height));
280 buf->flags = buffer->flags;
281 buf->field = V4L2_FIELD_NONE;
282 buf->timestamp = buffer->timestamp;
283 buf->sequence = buffer->sequence;
284 buf->m.offset = buffer->offset;
285 buf->length = buffer->length;
286
287 return kSuccessReturnValue;
288 }
289
streamon(const int * type)290 int streamon(const int* type) {
291 if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
292 return EINVAL;
293 frame_production_thread_.Start();
294 should_quit_frame_production_loop_.UnsafeResetForTesting();
295 frame_production_thread_.task_runner()->PostTask(
296 FROM_HERE,
297 base::BindOnce(&FakeV4L2Impl::OpenedDevice::RunFrameProductionLoop,
298 base::Unretained(this)));
299 return kSuccessReturnValue;
300 }
301
streamoff(const int * type)302 int streamoff(const int* type) {
303 if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
304 return EINVAL;
305 should_quit_frame_production_loop_.Set();
306 frame_production_thread_.Stop();
307 incoming_queue_ = std::queue<FakeV4L2Buffer*>();
308 outgoing_queue_ = std::queue<FakeV4L2Buffer*>();
309 return kSuccessReturnValue;
310 }
311
enum_framesizes(v4l2_frmsizeenum * frame_size)312 int enum_framesizes(v4l2_frmsizeenum* frame_size) {
313 if (frame_size->index > 0)
314 return -1;
315
316 frame_size->type = V4L2_FRMSIZE_TYPE_DISCRETE;
317 frame_size->discrete.width = kDefaultWidth;
318 frame_size->discrete.height = kDefaultHeight;
319 return 0;
320 }
321
enum_frameintervals(v4l2_frmivalenum * frame_interval)322 int enum_frameintervals(v4l2_frmivalenum* frame_interval) {
323 if (frame_interval->index > 0 || frame_interval->width != kDefaultWidth ||
324 frame_interval->height != kDefaultWidth) {
325 return -1;
326 }
327
328 frame_interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
329 frame_interval->discrete.numerator = kDefaultFrameInternvalNumerator;
330 frame_interval->discrete.denominator = kDefaultFrameInternvalDenominator;
331 return 0;
332 }
333
334 private:
RunFrameProductionLoop()335 void RunFrameProductionLoop() {
336 while (!should_quit_frame_production_loop_.IsSet()) {
337 MaybeProduceOneFrame();
338 // Sleep for a bit.
339 // We ignore the requested frame rate here, and just sleep for a fixed
340 // duration.
341 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
342 }
343 }
344
MaybeProduceOneFrame()345 void MaybeProduceOneFrame() {
346 // We do not actually produce any frame data. Just move a buffer from
347 // incoming queue to outgoing queue.
348 base::AutoLock lock(incoming_queue_lock_);
349 base::AutoLock lock2(outgoing_queue_lock_);
350 if (incoming_queue_.empty()) {
351 return;
352 }
353
354 auto* buffer = incoming_queue_.front();
355 gettimeofday(&buffer->timestamp, NULL);
356 static __u32 frame_counter = 0;
357 buffer->sequence = frame_counter++;
358 incoming_queue_.pop();
359 outgoing_queue_.push(buffer);
360 wait_for_outgoing_queue_event_.Signal();
361 }
362
363 const FakeV4L2DeviceConfig config_;
364 const int open_flags_;
365 v4l2_pix_format selected_format_;
366 v4l2_fract timeperframe_;
367 std::vector<FakeV4L2Buffer> device_buffers_;
368 std::queue<FakeV4L2Buffer*> incoming_queue_;
369 std::queue<FakeV4L2Buffer*> outgoing_queue_;
370 base::WaitableEvent wait_for_outgoing_queue_event_;
371 base::Thread frame_production_thread_;
372 base::AtomicFlag should_quit_frame_production_loop_;
373 base::Lock incoming_queue_lock_;
374 base::Lock outgoing_queue_lock_;
375 };
376
FakeV4L2Impl()377 FakeV4L2Impl::FakeV4L2Impl() : next_id_to_return_from_open_(1) {}
378
379 FakeV4L2Impl::~FakeV4L2Impl() = default;
380
AddDevice(const std::string & device_name,const FakeV4L2DeviceConfig & config)381 void FakeV4L2Impl::AddDevice(const std::string& device_name,
382 const FakeV4L2DeviceConfig& config) {
383 device_configs_.emplace(device_name, config);
384 }
385
open(const char * device_name,int flags)386 int FakeV4L2Impl::open(const char* device_name, int flags) {
387 std::string device_name_as_string(device_name);
388 auto device_configs_iter = device_configs_.find(device_name_as_string);
389 if (device_configs_iter == device_configs_.end())
390 return kInvalidId;
391
392 auto id_iter = device_name_to_open_id_map_.find(device_name_as_string);
393 if (id_iter != device_name_to_open_id_map_.end()) {
394 // Device is already open
395 return kInvalidId;
396 }
397
398 auto device_id = next_id_to_return_from_open_++;
399 device_name_to_open_id_map_.emplace(device_name_as_string, device_id);
400 opened_devices_.emplace(device_id, std::make_unique<OpenedDevice>(
401 device_configs_iter->second, flags));
402 return device_id;
403 }
404
close(int fd)405 int FakeV4L2Impl::close(int fd) {
406 auto device_iter = opened_devices_.find(fd);
407 if (device_iter == opened_devices_.end())
408 return kErrorReturnValue;
409 device_name_to_open_id_map_.erase(device_iter->second->device_id());
410 opened_devices_.erase(device_iter->first);
411 return kSuccessReturnValue;
412 }
413
ioctl(int fd,int request,void * argp)414 int FakeV4L2Impl::ioctl(int fd, int request, void* argp) {
415 auto device_iter = opened_devices_.find(fd);
416 if (device_iter == opened_devices_.end())
417 return EBADF;
418 auto* opened_device = device_iter->second.get();
419
420 switch (request) {
421 case VIDIOC_ENUM_FMT:
422 return opened_device->enum_fmt(reinterpret_cast<v4l2_fmtdesc*>(argp));
423 case VIDIOC_QUERYCAP:
424 return opened_device->querycap(reinterpret_cast<v4l2_capability*>(argp));
425 case VIDIOC_S_CTRL:
426 return opened_device->s_ctrl(reinterpret_cast<v4l2_control*>(argp));
427 case VIDIOC_S_EXT_CTRLS:
428 return opened_device->s_ext_ctrls(
429 reinterpret_cast<v4l2_ext_controls*>(argp));
430 case VIDIOC_QUERYCTRL:
431 return opened_device->queryctrl(reinterpret_cast<v4l2_queryctrl*>(argp));
432 case VIDIOC_S_FMT:
433 return opened_device->s_fmt(reinterpret_cast<v4l2_format*>(argp));
434 case VIDIOC_G_PARM:
435 return opened_device->g_parm(reinterpret_cast<v4l2_streamparm*>(argp));
436 case VIDIOC_S_PARM:
437 return opened_device->s_parm(reinterpret_cast<v4l2_streamparm*>(argp));
438 case VIDIOC_REQBUFS:
439 return opened_device->reqbufs(
440 reinterpret_cast<v4l2_requestbuffers*>(argp));
441 case VIDIOC_QUERYBUF:
442 return opened_device->querybuf(reinterpret_cast<v4l2_buffer*>(argp));
443 case VIDIOC_QBUF:
444 return opened_device->qbuf(reinterpret_cast<v4l2_buffer*>(argp));
445 case VIDIOC_DQBUF:
446 return opened_device->dqbuf(reinterpret_cast<v4l2_buffer*>(argp));
447 case VIDIOC_STREAMON:
448 return opened_device->streamon(reinterpret_cast<int*>(argp));
449 case VIDIOC_STREAMOFF:
450 return opened_device->streamoff(reinterpret_cast<int*>(argp));
451 case VIDIOC_ENUM_FRAMESIZES:
452 return opened_device->enum_framesizes(
453 reinterpret_cast<v4l2_frmsizeenum*>(argp));
454 case VIDIOC_ENUM_FRAMEINTERVALS:
455 return opened_device->enum_frameintervals(
456 reinterpret_cast<v4l2_frmivalenum*>(argp));
457
458 case VIDIOC_CROPCAP:
459 case VIDIOC_DBG_G_REGISTER:
460 case VIDIOC_DBG_S_REGISTER:
461 case VIDIOC_ENCODER_CMD:
462 case VIDIOC_TRY_ENCODER_CMD:
463 case VIDIOC_ENUMAUDIO:
464 case VIDIOC_ENUMAUDOUT:
465 case VIDIOC_ENUMINPUT:
466 case VIDIOC_ENUMOUTPUT:
467 case VIDIOC_ENUMSTD:
468 case VIDIOC_G_AUDIO:
469 case VIDIOC_S_AUDIO:
470 case VIDIOC_G_AUDOUT:
471 case VIDIOC_S_AUDOUT:
472 case VIDIOC_G_CROP:
473 case VIDIOC_S_CROP:
474 case VIDIOC_G_CTRL:
475 case VIDIOC_G_ENC_INDEX:
476 case VIDIOC_G_EXT_CTRLS:
477 case VIDIOC_TRY_EXT_CTRLS:
478 case VIDIOC_G_FBUF:
479 case VIDIOC_S_FBUF:
480 case VIDIOC_G_FMT:
481 case VIDIOC_TRY_FMT:
482 case VIDIOC_G_FREQUENCY:
483 case VIDIOC_S_FREQUENCY:
484 case VIDIOC_G_INPUT:
485 case VIDIOC_S_INPUT:
486 case VIDIOC_G_JPEGCOMP:
487 case VIDIOC_S_JPEGCOMP:
488 case VIDIOC_G_MODULATOR:
489 case VIDIOC_S_MODULATOR:
490 case VIDIOC_G_OUTPUT:
491 case VIDIOC_S_OUTPUT:
492 case VIDIOC_G_PRIORITY:
493 case VIDIOC_S_PRIORITY:
494 case VIDIOC_G_SLICED_VBI_CAP:
495 case VIDIOC_G_STD:
496 case VIDIOC_S_STD:
497 case VIDIOC_G_TUNER:
498 case VIDIOC_S_TUNER:
499 case VIDIOC_LOG_STATUS:
500 case VIDIOC_OVERLAY:
501 case VIDIOC_QUERYMENU:
502 case VIDIOC_QUERYSTD:
503 case VIDIOC_S_HW_FREQ_SEEK:
504 // Unsupported |request| code.
505 NOTREACHED() << "Unsupported request code " << request;
506 return kErrorReturnValue;
507 }
508
509 // Invalid |request|.
510 NOTREACHED();
511 return kErrorReturnValue;
512 }
513
514 // We ignore |start| in this implementation
mmap(void *,size_t length,int prot,int flags,int fd,off_t offset)515 void* FakeV4L2Impl::mmap(void* /*start*/,
516 size_t length,
517 int prot,
518 int flags,
519 int fd,
520 off_t offset) {
521 if (flags & MAP_FIXED) {
522 errno = EINVAL;
523 return MAP_FAILED;
524 }
525 if (prot != (PROT_READ | PROT_WRITE)) {
526 errno = EINVAL;
527 return MAP_FAILED;
528 }
529 auto device_iter = opened_devices_.find(fd);
530 if (device_iter == opened_devices_.end()) {
531 errno = EBADF;
532 return MAP_FAILED;
533 }
534 auto* opened_device = device_iter->second.get();
535 auto* buffer = opened_device->LookupBufferFromOffset(offset);
536 if (!buffer || (buffer->length != length)) {
537 errno = EINVAL;
538 return MAP_FAILED;
539 }
540 if (!buffer->data)
541 buffer->data = std::make_unique<uint8_t[]>(length);
542 return buffer->data.get();
543 }
544
munmap(void * start,size_t length)545 int FakeV4L2Impl::munmap(void* start, size_t length) {
546 return kSuccessReturnValue;
547 }
548
poll(struct pollfd * ufds,unsigned int nfds,int timeout)549 int FakeV4L2Impl::poll(struct pollfd* ufds, unsigned int nfds, int timeout) {
550 if (nfds != 1) {
551 // We only support polling of a single device.
552 errno = EINVAL;
553 return kErrorReturnValue;
554 }
555 pollfd& ufd = ufds[0];
556 auto device_iter = opened_devices_.find(ufd.fd);
557 if (device_iter == opened_devices_.end()) {
558 errno = EBADF;
559 return kErrorReturnValue;
560 }
561 auto* opened_device = device_iter->second.get();
562 if (ufd.events != POLLIN) {
563 // We only support waiting for data to become readable.
564 errno = EINVAL;
565 return kErrorReturnValue;
566 }
567 if (!opened_device->BlockUntilOutputQueueHasBuffer(timeout)) {
568 return 0;
569 }
570 ufd.revents |= POLLIN;
571 return 1;
572 }
573
574 } // namespace media
575