Home | History | Annotate | Download | only in video_capture
      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 "webrtc/modules/video_capture/video_capture_impl.h"
     12 
     13 #include <stdlib.h>
     14 
     15 #include "webrtc/base/trace_event.h"
     16 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
     17 #include "webrtc/modules/include/module_common_types.h"
     18 #include "webrtc/modules/video_capture/video_capture_config.h"
     19 #include "webrtc/system_wrappers/include/clock.h"
     20 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
     21 #include "webrtc/system_wrappers/include/logging.h"
     22 #include "webrtc/system_wrappers/include/ref_count.h"
     23 #include "webrtc/system_wrappers/include/tick_util.h"
     24 
     25 namespace webrtc
     26 {
     27 
     28 namespace videocapturemodule
     29 {
     30 VideoCaptureModule* VideoCaptureImpl::Create(
     31     const int32_t id,
     32     VideoCaptureExternal*& externalCapture)
     33 {
     34     RefCountImpl<VideoCaptureImpl>* implementation =
     35         new RefCountImpl<VideoCaptureImpl>(id);
     36     externalCapture = implementation;
     37     return implementation;
     38 }
     39 
     40 const char* VideoCaptureImpl::CurrentDeviceName() const
     41 {
     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 // static
     67 int32_t VideoCaptureImpl::RotationInDegrees(VideoRotation rotation,
     68                                             int* degrees) {
     69   switch (rotation) {
     70     case kVideoRotation_0:
     71       *degrees = 0;
     72       return 0;
     73     case kVideoRotation_90:
     74       *degrees = 90;
     75       return 0;
     76     case kVideoRotation_180:
     77       *degrees = 180;
     78       return 0;
     79     case kVideoRotation_270:
     80       *degrees = 270;
     81       return 0;
     82   }
     83   return -1;
     84 }
     85 
     86 // returns the number of milliseconds until the module want a worker thread to call Process
     87 int64_t VideoCaptureImpl::TimeUntilNextProcess()
     88 {
     89     CriticalSectionScoped cs(&_callBackCs);
     90     const int64_t kProcessIntervalMs = 300;
     91     return kProcessIntervalMs -
     92         (TickTime::Now() - _lastProcessTime).Milliseconds();
     93 }
     94 
     95 // Process any pending tasks such as timeouts
     96 int32_t VideoCaptureImpl::Process()
     97 {
     98     CriticalSectionScoped cs(&_callBackCs);
     99 
    100     const TickTime now = TickTime::Now();
    101     _lastProcessTime = TickTime::Now();
    102 
    103     // Handle No picture alarm
    104 
    105     if (_lastProcessFrameCount.Ticks() == _incomingFrameTimes[0].Ticks() &&
    106         _captureAlarm != Raised)
    107     {
    108         if (_noPictureAlarmCallBack && _captureCallBack)
    109         {
    110             _captureAlarm = Raised;
    111             _captureCallBack->OnNoPictureAlarm(_id, _captureAlarm);
    112         }
    113     }
    114     else if (_lastProcessFrameCount.Ticks() != _incomingFrameTimes[0].Ticks() &&
    115              _captureAlarm != Cleared)
    116     {
    117         if (_noPictureAlarmCallBack && _captureCallBack)
    118         {
    119             _captureAlarm = Cleared;
    120             _captureCallBack->OnNoPictureAlarm(_id, _captureAlarm);
    121 
    122         }
    123     }
    124 
    125     // Handle frame rate callback
    126     if ((now - _lastFrameRateCallbackTime).Milliseconds()
    127         > kFrameRateCallbackInterval)
    128     {
    129         if (_frameRateCallBack && _captureCallBack)
    130         {
    131             const uint32_t frameRate = CalculateFrameRate(now);
    132             _captureCallBack->OnCaptureFrameRate(_id, frameRate);
    133         }
    134         _lastFrameRateCallbackTime = now; // Can be set by EnableFrameRateCallback
    135 
    136     }
    137 
    138     _lastProcessFrameCount = _incomingFrameTimes[0];
    139 
    140     return 0;
    141 }
    142 
    143 VideoCaptureImpl::VideoCaptureImpl(const int32_t id)
    144     : _id(id),
    145       _deviceUniqueId(NULL),
    146       _apiCs(*CriticalSectionWrapper::CreateCriticalSection()),
    147       _captureDelay(0),
    148       _requestedCapability(),
    149       _callBackCs(*CriticalSectionWrapper::CreateCriticalSection()),
    150       _lastProcessTime(TickTime::Now()),
    151       _lastFrameRateCallbackTime(TickTime::Now()),
    152       _frameRateCallBack(false),
    153       _noPictureAlarmCallBack(false),
    154       _captureAlarm(Cleared),
    155       _setCaptureDelay(0),
    156       _dataCallBack(NULL),
    157       _captureCallBack(NULL),
    158       _lastProcessFrameCount(TickTime::Now()),
    159       _rotateFrame(kVideoRotation_0),
    160       apply_rotation_(true) {
    161     _requestedCapability.width = kDefaultWidth;
    162     _requestedCapability.height = kDefaultHeight;
    163     _requestedCapability.maxFPS = 30;
    164     _requestedCapability.rawType = kVideoI420;
    165     _requestedCapability.codecType = kVideoCodecUnknown;
    166     memset(_incomingFrameTimes, 0, sizeof(_incomingFrameTimes));
    167 }
    168 
    169 VideoCaptureImpl::~VideoCaptureImpl()
    170 {
    171     DeRegisterCaptureDataCallback();
    172     DeRegisterCaptureCallback();
    173     delete &_callBackCs;
    174     delete &_apiCs;
    175 
    176     if (_deviceUniqueId)
    177         delete[] _deviceUniqueId;
    178 }
    179 
    180 void VideoCaptureImpl::RegisterCaptureDataCallback(
    181     VideoCaptureDataCallback& dataCallBack) {
    182     CriticalSectionScoped cs(&_apiCs);
    183     CriticalSectionScoped cs2(&_callBackCs);
    184     _dataCallBack = &dataCallBack;
    185 }
    186 
    187 void VideoCaptureImpl::DeRegisterCaptureDataCallback() {
    188     CriticalSectionScoped cs(&_apiCs);
    189     CriticalSectionScoped cs2(&_callBackCs);
    190     _dataCallBack = NULL;
    191 }
    192 void VideoCaptureImpl::RegisterCaptureCallback(VideoCaptureFeedBack& callBack) {
    193 
    194     CriticalSectionScoped cs(&_apiCs);
    195     CriticalSectionScoped cs2(&_callBackCs);
    196     _captureCallBack = &callBack;
    197 }
    198 void VideoCaptureImpl::DeRegisterCaptureCallback() {
    199 
    200     CriticalSectionScoped cs(&_apiCs);
    201     CriticalSectionScoped cs2(&_callBackCs);
    202     _captureCallBack = NULL;
    203 }
    204 void VideoCaptureImpl::SetCaptureDelay(int32_t delayMS) {
    205     CriticalSectionScoped cs(&_apiCs);
    206     _captureDelay = delayMS;
    207 }
    208 int32_t VideoCaptureImpl::CaptureDelay()
    209 {
    210     CriticalSectionScoped cs(&_apiCs);
    211     return _setCaptureDelay;
    212 }
    213 
    214 int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) {
    215   UpdateFrameCount();  // frame count used for local frame rate callback.
    216 
    217   const bool callOnCaptureDelayChanged = _setCaptureDelay != _captureDelay;
    218   // Capture delay changed
    219   if (_setCaptureDelay != _captureDelay) {
    220       _setCaptureDelay = _captureDelay;
    221   }
    222 
    223   if (_dataCallBack) {
    224     if (callOnCaptureDelayChanged) {
    225       _dataCallBack->OnCaptureDelayChanged(_id, _captureDelay);
    226     }
    227     _dataCallBack->OnIncomingCapturedFrame(_id, captureFrame);
    228   }
    229 
    230   return 0;
    231 }
    232 
    233 int32_t VideoCaptureImpl::IncomingFrame(
    234     uint8_t* videoFrame,
    235     size_t videoFrameLength,
    236     const VideoCaptureCapability& frameInfo,
    237     int64_t captureTime/*=0*/)
    238 {
    239     CriticalSectionScoped cs(&_apiCs);
    240     CriticalSectionScoped cs2(&_callBackCs);
    241 
    242     const int32_t width = frameInfo.width;
    243     const int32_t height = frameInfo.height;
    244 
    245     TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime);
    246 
    247     if (frameInfo.codecType == kVideoCodecUnknown)
    248     {
    249         // Not encoded, convert to I420.
    250         const VideoType commonVideoType =
    251                   RawVideoTypeToCommonVideoVideoType(frameInfo.rawType);
    252 
    253         if (frameInfo.rawType != kVideoMJPEG &&
    254             CalcBufferSize(commonVideoType, width,
    255                            abs(height)) != videoFrameLength)
    256         {
    257             LOG(LS_ERROR) << "Wrong incoming frame length.";
    258             return -1;
    259         }
    260 
    261         int stride_y = width;
    262         int stride_uv = (width + 1) / 2;
    263         int target_width = width;
    264         int target_height = height;
    265 
    266         // SetApplyRotation doesn't take any lock. Make a local copy here.
    267         bool apply_rotation = apply_rotation_;
    268 
    269         if (apply_rotation) {
    270           // Rotating resolution when for 90/270 degree rotations.
    271           if (_rotateFrame == kVideoRotation_90 ||
    272               _rotateFrame == kVideoRotation_270) {
    273             target_width = abs(height);
    274             target_height = width;
    275           }
    276         }
    277 
    278         // TODO(mikhal): Update correct aligned stride values.
    279         //Calc16ByteAlignedStride(target_width, &stride_y, &stride_uv);
    280         // Setting absolute height (in case it was negative).
    281         // In Windows, the image starts bottom left, instead of top left.
    282         // Setting a negative source height, inverts the image (within LibYuv).
    283         int ret = _captureFrame.CreateEmptyFrame(target_width,
    284                                                  abs(target_height),
    285                                                  stride_y,
    286                                                  stride_uv, stride_uv);
    287         if (ret < 0)
    288         {
    289             LOG(LS_ERROR) << "Failed to create empty frame, this should only "
    290                              "happen due to bad parameters.";
    291             return -1;
    292         }
    293         const int conversionResult = ConvertToI420(
    294             commonVideoType, videoFrame, 0, 0,  // No cropping
    295             width, height, videoFrameLength,
    296             apply_rotation ? _rotateFrame : kVideoRotation_0, &_captureFrame);
    297         if (conversionResult < 0)
    298         {
    299           LOG(LS_ERROR) << "Failed to convert capture frame from type "
    300                         << frameInfo.rawType << "to I420.";
    301             return -1;
    302         }
    303 
    304         if (!apply_rotation) {
    305           _captureFrame.set_rotation(_rotateFrame);
    306         } else {
    307           _captureFrame.set_rotation(kVideoRotation_0);
    308         }
    309         _captureFrame.set_ntp_time_ms(captureTime);
    310         _captureFrame.set_render_time_ms(TickTime::MillisecondTimestamp());
    311 
    312         DeliverCapturedFrame(_captureFrame);
    313     }
    314     else // Encoded format
    315     {
    316         assert(false);
    317         return -1;
    318     }
    319 
    320     return 0;
    321 }
    322 
    323 int32_t VideoCaptureImpl::SetCaptureRotation(VideoRotation rotation) {
    324   CriticalSectionScoped cs(&_apiCs);
    325   CriticalSectionScoped cs2(&_callBackCs);
    326   _rotateFrame = rotation;
    327   return 0;
    328 }
    329 
    330 void VideoCaptureImpl::EnableFrameRateCallback(const bool enable) {
    331     CriticalSectionScoped cs(&_apiCs);
    332     CriticalSectionScoped cs2(&_callBackCs);
    333     _frameRateCallBack = enable;
    334     if (enable)
    335     {
    336         _lastFrameRateCallbackTime = TickTime::Now();
    337     }
    338 }
    339 
    340 bool VideoCaptureImpl::SetApplyRotation(bool enable) {
    341   // We can't take any lock here as it'll cause deadlock with IncomingFrame.
    342 
    343   // The effect of this is the last caller wins.
    344   apply_rotation_ = enable;
    345   return true;
    346 }
    347 
    348 void VideoCaptureImpl::EnableNoPictureAlarm(const bool enable) {
    349     CriticalSectionScoped cs(&_apiCs);
    350     CriticalSectionScoped cs2(&_callBackCs);
    351     _noPictureAlarmCallBack = enable;
    352 }
    353 
    354 void VideoCaptureImpl::UpdateFrameCount()
    355 {
    356     if (_incomingFrameTimes[0].MicrosecondTimestamp() == 0)
    357     {
    358         // first no shift
    359     }
    360     else
    361     {
    362         // shift
    363         for (int i = (kFrameRateCountHistorySize - 2); i >= 0; i--)
    364         {
    365             _incomingFrameTimes[i + 1] = _incomingFrameTimes[i];
    366         }
    367     }
    368     _incomingFrameTimes[0] = TickTime::Now();
    369 }
    370 
    371 uint32_t VideoCaptureImpl::CalculateFrameRate(const TickTime& now)
    372 {
    373     int32_t num = 0;
    374     int32_t nrOfFrames = 0;
    375     for (num = 1; num < (kFrameRateCountHistorySize - 1); num++)
    376     {
    377         if (_incomingFrameTimes[num].Ticks() <= 0
    378             || (now - _incomingFrameTimes[num]).Milliseconds() > kFrameRateHistoryWindowMs) // don't use data older than 2sec
    379         {
    380             break;
    381         }
    382         else
    383         {
    384             nrOfFrames++;
    385         }
    386     }
    387     if (num > 1)
    388     {
    389         int64_t diff = (now - _incomingFrameTimes[num - 1]).Milliseconds();
    390         if (diff > 0)
    391         {
    392             return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f);
    393         }
    394     }
    395 
    396     return nrOfFrames;
    397 }
    398 }  // namespace videocapturemodule
    399 }  // namespace webrtc
    400