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