tor-browser

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

video_capture_impl.cc (10993B)


      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/video_capture_impl.h"
     12 
     13 #include <cstdint>
     14 #include <cstdlib>
     15 #include <cstring>
     16 
     17 #include "api/scoped_refptr.h"
     18 #include "api/sequence_checker.h"
     19 #include "api/video/i420_buffer.h"
     20 #include "api/video/video_frame.h"
     21 #include "api/video/video_rotation.h"
     22 #include "api/video/video_sink_interface.h"
     23 #include "common_video/libyuv/include/webrtc_libyuv.h"
     24 #include "modules/video_capture/raw_video_sink_interface.h"
     25 #include "modules/video_capture/video_capture_config.h"
     26 #include "modules/video_capture/video_capture_defines.h"
     27 #include "rtc_base/checks.h"
     28 #include "rtc_base/logging.h"
     29 #include "rtc_base/race_checker.h"
     30 #include "rtc_base/synchronization/mutex.h"
     31 #include "rtc_base/time_utils.h"
     32 #include "rtc_base/trace_event.h"
     33 #include "system_wrappers/include/clock.h"
     34 #include "third_party/libyuv/include/libyuv/convert.h"
     35 #include "third_party/libyuv/include/libyuv/rotate.h"
     36 
     37 namespace webrtc {
     38 namespace videocapturemodule {
     39 
     40 const char* VideoCaptureImpl::CurrentDeviceName() const {
     41  RTC_DCHECK_RUN_ON(&api_checker_);
     42  return _deviceUniqueId;
     43 }
     44 
     45 // static
     46 int32_t VideoCaptureImpl::RotationFromDegrees(int degrees,
     47                                              VideoRotation* rotation) {
     48  switch (degrees) {
     49    case 0:
     50      *rotation = kVideoRotation_0;
     51      return 0;
     52    case 90:
     53      *rotation = kVideoRotation_90;
     54      return 0;
     55    case 180:
     56      *rotation = kVideoRotation_180;
     57      return 0;
     58    case 270:
     59      *rotation = kVideoRotation_270;
     60      return 0;
     61    default:
     62      return -1;
     63      ;
     64  }
     65 }
     66 
     67 // static
     68 int32_t VideoCaptureImpl::RotationInDegrees(VideoRotation rotation,
     69                                            int* degrees) {
     70  switch (rotation) {
     71    case kVideoRotation_0:
     72      *degrees = 0;
     73      return 0;
     74    case kVideoRotation_90:
     75      *degrees = 90;
     76      return 0;
     77    case kVideoRotation_180:
     78      *degrees = 180;
     79      return 0;
     80    case kVideoRotation_270:
     81      *degrees = 270;
     82      return 0;
     83  }
     84  return -1;
     85 }
     86 
     87 VideoCaptureImpl::VideoCaptureImpl(Clock* clock)
     88    : _deviceUniqueId(nullptr),
     89      _requestedCapability(),
     90      _lastProcessTimeNanos(clock->TimeInMicroseconds() * 1000),
     91      _lastFrameRateCallbackTimeNanos(clock->TimeInMicroseconds() * 1000),
     92      _rawDataCallBack(nullptr),
     93      _lastProcessFrameTimeNanos(clock->TimeInMicroseconds() * 1000),
     94      _rotateFrame(kVideoRotation_0),
     95      apply_rotation_(false),
     96      clock_(clock) {
     97  _requestedCapability.width = kDefaultWidth;
     98  _requestedCapability.height = kDefaultHeight;
     99  _requestedCapability.maxFPS = 30;
    100  _requestedCapability.videoType = VideoType::kI420;
    101  memset(_incomingFrameTimesNanos, 0, sizeof(_incomingFrameTimesNanos));
    102 }
    103 
    104 VideoCaptureImpl::~VideoCaptureImpl() {
    105  RTC_DCHECK_RUN_ON(&api_checker_);
    106  if (_deviceUniqueId)
    107    delete[] _deviceUniqueId;
    108 }
    109 
    110 void VideoCaptureImpl::RegisterCaptureDataCallback(
    111    VideoSinkInterface<VideoFrame>* dataCallBack) {
    112  MutexLock lock(&api_lock_);
    113  RTC_DCHECK(!_rawDataCallBack);
    114  _dataCallBacks.insert(dataCallBack);
    115 }
    116 
    117 void VideoCaptureImpl::RegisterCaptureDataCallback(
    118    RawVideoSinkInterface* dataCallBack) {
    119  MutexLock lock(&api_lock_);
    120  RTC_DCHECK(_dataCallBacks.empty());
    121  _rawDataCallBack = dataCallBack;
    122 }
    123 
    124 void VideoCaptureImpl::DeRegisterCaptureDataCallback(
    125    webrtc::VideoSinkInterface<VideoFrame>* dataCallBack) {
    126  MutexLock lock(&api_lock_);
    127  auto it = _dataCallBacks.find(dataCallBack);
    128  if (it != _dataCallBacks.end()) {
    129    _dataCallBacks.erase(it);
    130  }
    131  _rawDataCallBack = nullptr;
    132 }
    133 
    134 int32_t VideoCaptureImpl::StopCaptureIfAllClientsClose() {
    135  RTC_DCHECK_RUN_ON(&api_checker_);
    136  {
    137    MutexLock lock(&api_lock_);
    138    if (!_dataCallBacks.empty()) {
    139      return 0;
    140    }
    141  }
    142  return StopCapture();
    143 }
    144 
    145 int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) {
    146  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    147 
    148  UpdateFrameCount();  // frame count used for local frame rate callback.
    149 
    150  for (auto* dataCallBack : _dataCallBacks) {
    151    dataCallBack->OnFrame(captureFrame);
    152  }
    153 
    154  return 0;
    155 }
    156 
    157 void VideoCaptureImpl::DeliverRawFrame(uint8_t* videoFrame,
    158                                       size_t videoFrameLength,
    159                                       const VideoCaptureCapability& frameInfo,
    160                                       int64_t captureTime) {
    161  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    162 
    163  UpdateFrameCount();
    164  _rawDataCallBack->OnRawFrame(videoFrame, videoFrameLength, frameInfo,
    165                               _rotateFrame, captureTime);
    166 }
    167 
    168 int32_t VideoCaptureImpl::IncomingFrame(uint8_t* videoFrame,
    169                                        size_t videoFrameLength,
    170                                        const VideoCaptureCapability& frameInfo,
    171                                        int64_t captureTime /*=0*/) {
    172  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    173  MutexLock lock(&api_lock_);
    174 
    175  const int32_t width = frameInfo.width;
    176  const int32_t height = frameInfo.height;
    177 
    178  TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime);
    179 
    180  if (_rawDataCallBack) {
    181    DeliverRawFrame(videoFrame, videoFrameLength, frameInfo, captureTime);
    182    return 0;
    183  }
    184 
    185  // Not encoded, convert to I420.
    186  if (frameInfo.videoType != VideoType::kMJPEG) {
    187    // Allow buffers larger than expected. On linux gstreamer allocates buffers
    188    // page-aligned and v4l2loopback passes us the buffer size verbatim which
    189    // for most cases is larger than expected.
    190    // See https://github.com/umlaeute/v4l2loopback/issues/190.
    191    if (auto size = CalcBufferSize(frameInfo.videoType, width, abs(height));
    192        videoFrameLength < size) {
    193      RTC_LOG(LS_ERROR) << "Wrong incoming frame length. Expected " << size
    194                        << ", Got " << videoFrameLength << ".";
    195      return -1;
    196    }
    197  }
    198 
    199  int target_width = width;
    200  int target_height = abs(height);
    201 
    202  if (apply_rotation_) {
    203    // Rotating resolution when for 90/270 degree rotations.
    204    if (_rotateFrame == kVideoRotation_90 ||
    205        _rotateFrame == kVideoRotation_270) {
    206      target_width = abs(height);
    207      target_height = width;
    208    }
    209  }
    210 
    211  int stride_y = target_width;
    212  int stride_uv = (target_width + 1) / 2;
    213 
    214  // Setting absolute height (in case it was negative).
    215  // In Windows, the image starts bottom left, instead of top left.
    216  // Setting a negative source height, inverts the image (within LibYuv).
    217  scoped_refptr<I420Buffer> buffer = I420Buffer::Create(
    218      target_width, target_height, stride_y, stride_uv, stride_uv);
    219 
    220  libyuv::RotationMode rotation_mode = libyuv::kRotate0;
    221  if (apply_rotation_) {
    222    switch (_rotateFrame) {
    223      case kVideoRotation_0:
    224        rotation_mode = libyuv::kRotate0;
    225        break;
    226      case kVideoRotation_90:
    227        rotation_mode = libyuv::kRotate90;
    228        break;
    229      case kVideoRotation_180:
    230        rotation_mode = libyuv::kRotate180;
    231        break;
    232      case kVideoRotation_270:
    233        rotation_mode = libyuv::kRotate270;
    234        break;
    235    }
    236  }
    237 
    238  int dst_width = buffer->width();
    239  int dst_height = buffer->height();
    240 
    241  // LibYuv expects pre-rotation_mode values for dst.
    242  // Stride values should correspond to the destination values.
    243  if (rotation_mode == libyuv::kRotate90 || rotation_mode == libyuv::kRotate270) {
    244    std::swap(dst_width, dst_height);
    245  }
    246 
    247  const int conversionResult = libyuv::ConvertToI420(
    248      videoFrame, videoFrameLength, buffer->MutableDataY(), buffer->StrideY(),
    249      buffer->MutableDataU(), buffer->StrideU(), buffer->MutableDataV(),
    250      buffer->StrideV(), 0, 0,  // No Cropping
    251      width, height, dst_width, dst_height, rotation_mode,
    252      ConvertVideoType(frameInfo.videoType));
    253  if (conversionResult != 0) {
    254    RTC_LOG(LS_ERROR) << "Failed to convert capture frame from type "
    255                      << static_cast<int>(frameInfo.videoType) << "to I420.";
    256    return -1;
    257  }
    258 
    259  VideoFrame captureFrame =
    260      VideoFrame::Builder()
    261          .set_video_frame_buffer(buffer)
    262          .set_rtp_timestamp(0)
    263          .set_timestamp_ms(clock_->TimeInMilliseconds())
    264          .set_rotation(!apply_rotation_ ? _rotateFrame : kVideoRotation_0)
    265          .build();
    266  captureFrame.set_ntp_time_ms(captureTime);
    267 
    268  // This is one ugly hack to let CamerasParent know what rotation
    269  // the frame was captured at. Note that this goes against the intended
    270  // meaning of rotation of the frame (how to rotate it before rendering).
    271  // We do this so CamerasChild can scale to the proper dimensions
    272  // later on in the pipe.
    273  captureFrame.set_rotation(_rotateFrame);
    274 
    275  DeliverCapturedFrame(captureFrame);
    276 
    277  return 0;
    278 }
    279 
    280 int32_t VideoCaptureImpl::StartCapture(
    281    const VideoCaptureCapability& capability) {
    282  RTC_DCHECK_RUN_ON(&api_checker_);
    283  _requestedCapability = capability;
    284  return -1;
    285 }
    286 
    287 int32_t VideoCaptureImpl::StopCapture() {
    288  return -1;
    289 }
    290 
    291 bool VideoCaptureImpl::CaptureStarted() {
    292  return false;
    293 }
    294 
    295 int32_t VideoCaptureImpl::CaptureSettings(
    296    VideoCaptureCapability& /*settings*/) {
    297  return -1;
    298 }
    299 
    300 int32_t VideoCaptureImpl::SetCaptureRotation(VideoRotation rotation) {
    301  MutexLock lock(&api_lock_);
    302  _rotateFrame = rotation;
    303  return 0;
    304 }
    305 
    306 bool VideoCaptureImpl::SetApplyRotation(bool enable) {
    307  MutexLock lock(&api_lock_);
    308  apply_rotation_ = enable;
    309  return true;
    310 }
    311 
    312 bool VideoCaptureImpl::GetApplyRotation() {
    313  MutexLock lock(&api_lock_);
    314  return apply_rotation_;
    315 }
    316 
    317 void VideoCaptureImpl::UpdateFrameCount() {
    318  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    319 
    320  if (_incomingFrameTimesNanos[0] / kNumNanosecsPerMicrosec == 0) {
    321    // first no shift
    322  } else {
    323    // shift
    324    for (int i = (kFrameRateCountHistorySize - 2); i >= 0; --i) {
    325      _incomingFrameTimesNanos[i + 1] = _incomingFrameTimesNanos[i];
    326    }
    327  }
    328  _incomingFrameTimesNanos[0] = clock_->TimeInMicroseconds() * 1000;
    329 }
    330 
    331 uint32_t VideoCaptureImpl::CalculateFrameRate(int64_t now_ns) {
    332  RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
    333 
    334  int32_t num = 0;
    335  int32_t nrOfFrames = 0;
    336  for (num = 1; num < (kFrameRateCountHistorySize - 1); ++num) {
    337    if (_incomingFrameTimesNanos[num] <= 0 ||
    338        (now_ns - _incomingFrameTimesNanos[num]) / kNumNanosecsPerMillisec >
    339            kFrameRateHistoryWindowMs) {  // don't use data older than 2sec
    340      break;
    341    } else {
    342      nrOfFrames++;
    343    }
    344  }
    345  if (num > 1) {
    346    int64_t diff =
    347        (now_ns - _incomingFrameTimesNanos[num - 1]) / kNumNanosecsPerMillisec;
    348    if (diff > 0) {
    349      return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f);
    350    }
    351  }
    352 
    353  return nrOfFrames;
    354 }
    355 }  // namespace videocapturemodule
    356 }  // namespace webrtc