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
25namespace webrtc
26{
27namespace videocapturemodule
28{
29VideoCaptureModule* 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
39const char* VideoCaptureImpl::CurrentDeviceName() const
40{
41    return _deviceUniqueId;
42}
43
44// static
45int32_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
66int32_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
85int32_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
92int32_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
103int32_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
150VideoCaptureImpl::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
179VideoCaptureImpl::~VideoCaptureImpl()
180{
181    DeRegisterCaptureDataCallback();
182    DeRegisterCaptureCallback();
183    delete &_callBackCs;
184    delete &_apiCs;
185
186    if (_deviceUniqueId)
187        delete[] _deviceUniqueId;
188}
189
190void VideoCaptureImpl::RegisterCaptureDataCallback(
191    VideoCaptureDataCallback& dataCallBack) {
192    CriticalSectionScoped cs(&_apiCs);
193    CriticalSectionScoped cs2(&_callBackCs);
194    _dataCallBack = &dataCallBack;
195}
196
197void VideoCaptureImpl::DeRegisterCaptureDataCallback() {
198    CriticalSectionScoped cs(&_apiCs);
199    CriticalSectionScoped cs2(&_callBackCs);
200    _dataCallBack = NULL;
201}
202void VideoCaptureImpl::RegisterCaptureCallback(VideoCaptureFeedBack& callBack) {
203
204    CriticalSectionScoped cs(&_apiCs);
205    CriticalSectionScoped cs2(&_callBackCs);
206    _captureCallBack = &callBack;
207}
208void VideoCaptureImpl::DeRegisterCaptureCallback() {
209
210    CriticalSectionScoped cs(&_apiCs);
211    CriticalSectionScoped cs2(&_callBackCs);
212    _captureCallBack = NULL;
213}
214void VideoCaptureImpl::SetCaptureDelay(int32_t delayMS) {
215    CriticalSectionScoped cs(&_apiCs);
216    _captureDelay = delayMS;
217}
218int32_t VideoCaptureImpl::CaptureDelay()
219{
220    CriticalSectionScoped cs(&_apiCs);
221    return _setCaptureDelay;
222}
223
224int32_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
257int32_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
333int32_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
343int32_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
365void 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
375void VideoCaptureImpl::EnableNoPictureAlarm(const bool enable) {
376    CriticalSectionScoped cs(&_apiCs);
377    CriticalSectionScoped cs2(&_callBackCs);
378    _noPictureAlarmCallBack = enable;
379}
380
381void 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
398uint32_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