tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

video_capture_v4l2.cc (15993B)


      1 /*
      2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3 *
      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 
     11 #include "modules/video_capture/linux/video_capture_v4l2.h"
     12 
     13 #include <fcntl.h>
     14 #if defined(__NetBSD__) || defined(__OpenBSD__) // WEBRTC_BSD
     15 #include <sys/videoio.h>
     16 #elif defined(__sun)
     17 #include <sys/videodev2.h>
     18 #else
     19 #include <linux/videodev2.h>
     20 #endif
     21 #include <poll.h>
     22 #include <sys/ioctl.h>
     23 #include <sys/mman.h>
     24 #include <sys/select.h>
     25 #include <unistd.h>
     26 
     27 #include <cerrno>
     28 #include <cstdint>
     29 #include <cstdio>
     30 #include <cstring>
     31 #include <new>
     32 
     33 #include "api/sequence_checker.h"
     34 #include "common_video/libyuv/include/webrtc_libyuv.h"
     35 #include "media/base/video_common.h"
     36 #include "modules/video_capture/video_capture_defines.h"
     37 #include "modules/video_capture/video_capture_impl.h"
     38 #include "rtc_base/checks.h"
     39 #include "rtc_base/logging.h"
     40 #include "rtc_base/platform_thread.h"
     41 #include "rtc_base/race_checker.h"
     42 #include "rtc_base/synchronization/mutex.h"
     43 #include "system_wrappers/include/clock.h"
     44 
     45 // These defines are here to support building on kernel 3.16 which some
     46 // downstream projects, e.g. Firefox, use.
     47 // TODO(apehrson): Remove them and their undefs when no longer needed.
     48 #ifndef V4L2_PIX_FMT_ABGR32
     49 #define ABGR32_OVERRIDE 1
     50 #define V4L2_PIX_FMT_ABGR32 v4l2_fourcc('A', 'R', '2', '4')
     51 #endif
     52 
     53 #ifndef V4L2_PIX_FMT_ARGB32
     54 #define ARGB32_OVERRIDE 1
     55 #define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4')
     56 #endif
     57 
     58 #ifndef V4L2_PIX_FMT_RGBA32
     59 #define RGBA32_OVERRIDE 1
     60 #define V4L2_PIX_FMT_RGBA32 v4l2_fourcc('A', 'B', '2', '4')
     61 #endif
     62 
     63 namespace webrtc {
     64 namespace videocapturemodule {
     65 VideoCaptureModuleV4L2::VideoCaptureModuleV4L2(Clock* clock)
     66    : VideoCaptureImpl(clock),
     67      _deviceId(-1),
     68      _deviceFd(-1),
     69      _buffersAllocatedByDevice(-1),
     70      _streaming(false),
     71      _captureStarted(false),
     72      _pool(nullptr) {}
     73 
     74 int32_t VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8) {
     75  RTC_DCHECK_RUN_ON(&api_checker_);
     76 
     77  int len = strlen((const char*)deviceUniqueIdUTF8);
     78  _deviceUniqueId = new (std::nothrow) char[len + 1];
     79  if (_deviceUniqueId) {
     80    memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1);
     81  }
     82 
     83  int fd;
     84  char device[32];
     85  bool found = false;
     86 
     87  /* detect /dev/video [0-63] entries */
     88  int n;
     89  for (n = 0; n < 64; n++) {
     90    snprintf(device, sizeof(device), "/dev/video%d", n);
     91    if ((fd = open(device, O_RDONLY)) != -1) {
     92      // query device capabilities
     93      struct v4l2_capability cap;
     94      if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
     95        if (cap.bus_info[0] != 0) {
     96          if (strncmp((const char*)cap.bus_info,
     97                      (const char*)deviceUniqueIdUTF8,
     98                      strlen((const char*)deviceUniqueIdUTF8)) ==
     99              0) {  // match with device id
    100            close(fd);
    101            found = true;
    102            break;  // fd matches with device unique id supplied
    103          }
    104        }
    105      }
    106      close(fd);  // close since this is not the matching device
    107    }
    108  }
    109  if (!found) {
    110    RTC_LOG(LS_INFO) << "no matching device found";
    111    return -1;
    112  }
    113  _deviceId = n;  // store the device id
    114  return 0;
    115 }
    116 
    117 VideoCaptureModuleV4L2::~VideoCaptureModuleV4L2() {
    118  RTC_DCHECK_RUN_ON(&api_checker_);
    119  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    120 
    121  StopCapture();
    122  if (_deviceFd != -1)
    123    close(_deviceFd);
    124 }
    125 
    126 int32_t VideoCaptureModuleV4L2::StartCapture(
    127    const VideoCaptureCapability& capability) {
    128  RTC_DCHECK_RUN_ON(&api_checker_);
    129 
    130  if (_captureStarted) {
    131    if (capability == _requestedCapability) {
    132      return 0;
    133    } else {
    134      StopCapture();
    135    }
    136  }
    137 
    138  {
    139  // We don't want members above to be guarded by capture_checker_ as
    140  // it's meant to be for members that are accessed on the API thread
    141  // only when we are not capturing. The code above can be called many
    142  // times while sharing instance of VideoCaptureV4L2 between websites
    143  // and therefore it would not follow the requirements of this checker.
    144  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    145 
    146  // Set a baseline of configured parameters. It is updated here during
    147  // configuration, then read from the capture thread.
    148  configured_capability_ = capability;
    149 
    150  MutexLock lock(&capture_lock_);
    151  // first open /dev/video device
    152  char device[20];
    153  snprintf(device, sizeof(device), "/dev/video%d", _deviceId);
    154 
    155  if ((_deviceFd = open(device, O_RDWR | O_NONBLOCK, 0)) < 0) {
    156    RTC_LOG(LS_INFO) << "error in opening " << device << " errono = " << errno;
    157    return -1;
    158  }
    159 
    160  // Supported video formats in preferred order.
    161  // If the requested resolution is larger than VGA, we prefer MJPEG. Go for
    162  // I420 otherwise.
    163  unsigned int hdFmts[] = {
    164      V4L2_PIX_FMT_MJPEG,  V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420,
    165      V4L2_PIX_FMT_YUYV,   V4L2_PIX_FMT_UYVY,   V4L2_PIX_FMT_NV12,
    166      V4L2_PIX_FMT_ABGR32, V4L2_PIX_FMT_ARGB32, V4L2_PIX_FMT_RGBA32,
    167      V4L2_PIX_FMT_BGR32,  V4L2_PIX_FMT_RGB32,  V4L2_PIX_FMT_BGR24,
    168      V4L2_PIX_FMT_RGB24,  V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_JPEG,
    169  };
    170  unsigned int sdFmts[] = {
    171      V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUYV,
    172      V4L2_PIX_FMT_UYVY,   V4L2_PIX_FMT_NV12,   V4L2_PIX_FMT_ABGR32,
    173      V4L2_PIX_FMT_ARGB32, V4L2_PIX_FMT_RGBA32, V4L2_PIX_FMT_BGR32,
    174      V4L2_PIX_FMT_RGB32,  V4L2_PIX_FMT_BGR24,  V4L2_PIX_FMT_RGB24,
    175      V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_MJPEG,  V4L2_PIX_FMT_JPEG,
    176  };
    177  const bool isHd = capability.width > 640 || capability.height > 480;
    178  unsigned int* fmts = isHd ? hdFmts : sdFmts;
    179  static_assert(sizeof(hdFmts) == sizeof(sdFmts));
    180  constexpr int nFormats = sizeof(hdFmts) / sizeof(unsigned int);
    181 
    182  // Enumerate image formats.
    183  struct v4l2_fmtdesc fmt;
    184  int fmtsIdx = nFormats;
    185  memset(&fmt, 0, sizeof(fmt));
    186  fmt.index = 0;
    187  fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    188  RTC_LOG(LS_INFO) << "Video Capture enumerats supported image formats:";
    189  while (ioctl(_deviceFd, VIDIOC_ENUM_FMT, &fmt) == 0) {
    190    RTC_LOG(LS_INFO) << "  { pixelformat = " << GetFourccName(fmt.pixelformat)
    191                     << ", description = '" << fmt.description << "' }";
    192    // Match the preferred order.
    193    for (int i = 0; i < nFormats; i++) {
    194      if (fmt.pixelformat == fmts[i] && i < fmtsIdx)
    195        fmtsIdx = i;
    196    }
    197    // Keep enumerating.
    198    fmt.index++;
    199  }
    200 
    201  if (fmtsIdx == nFormats) {
    202    RTC_LOG(LS_INFO) << "no supporting video formats found";
    203    return -1;
    204  } else {
    205    RTC_LOG(LS_INFO) << "We prefer format " << GetFourccName(fmts[fmtsIdx]);
    206  }
    207 
    208  struct v4l2_format video_fmt;
    209  memset(&video_fmt, 0, sizeof(struct v4l2_format));
    210  video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    211  video_fmt.fmt.pix.sizeimage = 0;
    212  video_fmt.fmt.pix.width = capability.width;
    213  video_fmt.fmt.pix.height = capability.height;
    214  video_fmt.fmt.pix.pixelformat = fmts[fmtsIdx];
    215 
    216  if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
    217    configured_capability_.videoType = VideoType::kYUY2;
    218  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
    219    configured_capability_.videoType = VideoType::kI420;
    220  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420)
    221    configured_capability_.videoType = VideoType::kYV12;
    222  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY)
    223    configured_capability_.videoType = VideoType::kUYVY;
    224  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12)
    225    configured_capability_.videoType = VideoType::kNV12;
    226  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24)
    227    configured_capability_.videoType = VideoType::kRGB24;
    228  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
    229    configured_capability_.videoType = VideoType::kBGR24;
    230  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565)
    231    configured_capability_.videoType = VideoType::kRGB565;
    232  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_ABGR32 ||
    233           video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32)
    234    configured_capability_.videoType = VideoType::kARGB;
    235  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_ARGB32 ||
    236           video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32)
    237    configured_capability_.videoType = VideoType::kBGRA;
    238  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGBA32)
    239    configured_capability_.videoType = VideoType::kABGR;
    240  else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG ||
    241           video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
    242    configured_capability_.videoType = VideoType::kMJPEG;
    243  else
    244    RTC_DCHECK_NOTREACHED();
    245 
    246  // set format and frame size now
    247  if (ioctl(_deviceFd, VIDIOC_S_FMT, &video_fmt) < 0) {
    248    RTC_LOG(LS_INFO) << "error in VIDIOC_S_FMT, errno = " << errno;
    249    return -1;
    250  }
    251 
    252  // initialize current width and height
    253  configured_capability_.width = video_fmt.fmt.pix.width;
    254  configured_capability_.height = video_fmt.fmt.pix.height;
    255 
    256  // Trying to set frame rate, before check driver capability.
    257  bool driver_framerate_support = true;
    258  struct v4l2_streamparm streamparms;
    259  memset(&streamparms, 0, sizeof(streamparms));
    260  streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    261  if (ioctl(_deviceFd, VIDIOC_G_PARM, &streamparms) < 0) {
    262    RTC_LOG(LS_INFO) << "error in VIDIOC_G_PARM errno = " << errno;
    263    driver_framerate_support = false;
    264    // continue
    265  } else {
    266    // check the capability flag is set to V4L2_CAP_TIMEPERFRAME.
    267    if (streamparms.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
    268      // driver supports the feature. Set required framerate.
    269      memset(&streamparms, 0, sizeof(streamparms));
    270      streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    271      streamparms.parm.capture.timeperframe.numerator = 1;
    272      streamparms.parm.capture.timeperframe.denominator = capability.maxFPS;
    273      if (ioctl(_deviceFd, VIDIOC_S_PARM, &streamparms) < 0) {
    274        RTC_LOG(LS_INFO) << "Failed to set the framerate. errno=" << errno;
    275        driver_framerate_support = false;
    276      }
    277    }
    278  }
    279  // If driver doesn't support framerate control, need to hardcode.
    280  // Hardcoding the value based on the frame size.
    281  if (!driver_framerate_support) {
    282    if (configured_capability_.width >= 800 &&
    283        configured_capability_.videoType != VideoType::kMJPEG) {
    284      configured_capability_.maxFPS = 15;
    285    } else {
    286      configured_capability_.maxFPS = 30;
    287    }
    288  }
    289 
    290  if (!AllocateVideoBuffers()) {
    291    RTC_LOG(LS_INFO) << "failed to allocate video capture buffers";
    292    return -1;
    293  }
    294 
    295  // Needed to start UVC camera - from the uvcview application
    296  enum v4l2_buf_type type;
    297  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    298  if (ioctl(_deviceFd, VIDIOC_STREAMON, &type) == -1) {
    299    RTC_LOG(LS_INFO) << "Failed to turn on stream";
    300    return -1;
    301  }
    302 
    303  _requestedCapability = capability;
    304  _captureStarted = true;
    305  _streaming = true;
    306 
    307  // start capture thread;
    308  if (!_captureThread.empty()) {
    309    return 0;
    310  }
    311 
    312  quit_ = false;
    313  }
    314 
    315  _captureThread = PlatformThread::SpawnJoinable(
    316      [self = scoped_refptr(this)] {
    317        while (self->CaptureProcess()) {
    318        }
    319      },
    320      "CaptureThread", ThreadAttributes().SetPriority(ThreadPriority::kHigh));
    321  return 0;
    322 }
    323 
    324 int32_t VideoCaptureModuleV4L2::StopCapture() {
    325  RTC_DCHECK_RUN_ON(&api_checker_);
    326 
    327  if (!_captureThread.empty()) {
    328    {
    329      MutexLock lock(&capture_lock_);
    330      quit_ = true;
    331    }
    332    // Make sure the capture thread stops using the mutex.
    333    _captureThread.Finalize();
    334  }
    335 
    336  _captureStarted = false;
    337 
    338  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    339  MutexLock lock(&capture_lock_);
    340  if (_streaming) {
    341    _streaming = false;
    342 
    343    DeAllocateVideoBuffers();
    344    close(_deviceFd);
    345    _deviceFd = -1;
    346 
    347    _requestedCapability = configured_capability_ = VideoCaptureCapability();
    348  }
    349 
    350  return 0;
    351 }
    352 
    353 // critical section protected by the caller
    354 
    355 bool VideoCaptureModuleV4L2::AllocateVideoBuffers() {
    356  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    357  struct v4l2_requestbuffers rbuffer;
    358  memset(&rbuffer, 0, sizeof(v4l2_requestbuffers));
    359 
    360  rbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    361  rbuffer.memory = V4L2_MEMORY_MMAP;
    362  rbuffer.count = kNoOfV4L2Bufffers;
    363 
    364  if (ioctl(_deviceFd, VIDIOC_REQBUFS, &rbuffer) < 0) {
    365    RTC_LOG(LS_INFO) << "Could not get buffers from device. errno = " << errno;
    366    return false;
    367  }
    368 
    369  if (rbuffer.count > kNoOfV4L2Bufffers)
    370    rbuffer.count = kNoOfV4L2Bufffers;
    371 
    372  _buffersAllocatedByDevice = rbuffer.count;
    373 
    374  // Map the buffers
    375  _pool = new Buffer[rbuffer.count];
    376 
    377  for (unsigned int i = 0; i < rbuffer.count; i++) {
    378    struct v4l2_buffer buffer;
    379    memset(&buffer, 0, sizeof(v4l2_buffer));
    380    buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    381    buffer.memory = V4L2_MEMORY_MMAP;
    382    buffer.index = i;
    383 
    384    if (ioctl(_deviceFd, VIDIOC_QUERYBUF, &buffer) < 0) {
    385      return false;
    386    }
    387 
    388    _pool[i].start = mmap(nullptr, buffer.length, PROT_READ | PROT_WRITE,
    389                          MAP_SHARED, _deviceFd, buffer.m.offset);
    390 
    391    if (MAP_FAILED == _pool[i].start) {
    392      for (unsigned int j = 0; j < i; j++)
    393        munmap(_pool[j].start, _pool[j].length);
    394      return false;
    395    }
    396 
    397    _pool[i].length = buffer.length;
    398 
    399    if (ioctl(_deviceFd, VIDIOC_QBUF, &buffer) < 0) {
    400      return false;
    401    }
    402  }
    403  return true;
    404 }
    405 
    406 bool VideoCaptureModuleV4L2::DeAllocateVideoBuffers() {
    407  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    408  // unmap buffers
    409  for (int i = 0; i < _buffersAllocatedByDevice; i++)
    410    munmap(_pool[i].start, _pool[i].length);
    411 
    412  delete[] _pool;
    413 
    414  // turn off stream
    415  enum v4l2_buf_type type;
    416  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    417  if (ioctl(_deviceFd, VIDIOC_STREAMOFF, &type) < 0) {
    418    RTC_LOG(LS_INFO) << "VIDIOC_STREAMOFF error. errno: " << errno;
    419  }
    420 
    421  return true;
    422 }
    423 
    424 bool VideoCaptureModuleV4L2::CaptureStarted() {
    425  RTC_DCHECK_RUN_ON(&api_checker_);
    426  return _captureStarted;
    427 }
    428 
    429 bool VideoCaptureModuleV4L2::CaptureProcess() {
    430  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    431 
    432  int retVal = 0;
    433  struct pollfd rSet;
    434 
    435  rSet.fd = _deviceFd;
    436  rSet.events = POLLIN;
    437  rSet.revents = 0;
    438 
    439  retVal = poll(&rSet, 1, 1000);
    440 
    441  {
    442    MutexLock lock(&capture_lock_);
    443 
    444    if (quit_) {
    445      return false;
    446    }
    447 
    448    if (retVal < 0 && errno != EINTR) {  // continue if interrupted
    449      // poll failed
    450      return false;
    451    } else if (retVal == 0) {
    452      // poll timed out
    453      return true;
    454    } else if (!(rSet.revents & POLLIN)) {
    455      // not event on camera handle
    456      return true;
    457    }
    458 
    459    if (_streaming) {
    460      struct v4l2_buffer buf;
    461      memset(&buf, 0, sizeof(struct v4l2_buffer));
    462      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    463      buf.memory = V4L2_MEMORY_MMAP;
    464      // dequeue a buffer - repeat until dequeued properly!
    465      while (ioctl(_deviceFd, VIDIOC_DQBUF, &buf) < 0) {
    466        if (errno != EINTR) {
    467          RTC_LOG(LS_INFO) << "could not sync on a buffer on device "
    468                           << strerror(errno);
    469          return true;
    470        }
    471      }
    472 
    473      // convert to to I420 if needed
    474      IncomingFrame(reinterpret_cast<uint8_t*>(_pool[buf.index].start),
    475                    buf.bytesused, configured_capability_);
    476      // enqueue the buffer again
    477      if (ioctl(_deviceFd, VIDIOC_QBUF, &buf) == -1) {
    478        RTC_LOG(LS_INFO) << "Failed to enqueue capture buffer";
    479      }
    480    }
    481  }
    482  usleep(0);
    483  return true;
    484 }
    485 
    486 int32_t VideoCaptureModuleV4L2::CaptureSettings(
    487    VideoCaptureCapability& settings) {
    488  RTC_DCHECK_RUN_ON(&api_checker_);
    489  settings = _requestedCapability;
    490 
    491  return 0;
    492 }
    493 }  // namespace videocapturemodule
    494 }  // namespace webrtc
    495 
    496 #ifdef ABGR32_OVERRIDE
    497 #undef ABGR32_OVERRIDE
    498 #undef V4L2_PIX_FMT_ABGR32
    499 #endif
    500 
    501 #ifdef ARGB32_OVERRIDE
    502 #undef ARGB32_OVERRIDE
    503 #undef V4L2_PIX_FMT_ARGB32
    504 #endif
    505 
    506 #ifdef RGBA32_OVERRIDE
    507 #undef RGBA32_OVERRIDE
    508 #undef V4L2_PIX_FMT_RGBA32
    509 #endif