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