blob: 16b2b458c25bc7608da4645a7a99433571578fe0 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mallinath@webrtc.org12984f02012-02-16 18:18:21 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000011#include "webrtc/modules/video_capture/video_capture_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
elham@webrtc.org5f49dba2012-04-23 21:24:02 +000013#include <stdlib.h>
14
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000015#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"
pbos@webrtc.org3d5cb332014-05-14 08:42:07 +000020#include "webrtc/system_wrappers/interface/logging.h"
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000021#include "webrtc/system_wrappers/interface/ref_count.h"
22#include "webrtc/system_wrappers/interface/tick_util.h"
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000023#include "webrtc/system_wrappers/interface/trace_event.h"
24
niklase@google.com470e71d2011-07-07 08:21:25 +000025namespace webrtc
26{
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000027namespace videocapturemodule
niklase@google.com470e71d2011-07-07 08:21:25 +000028{
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000029VideoCaptureModule* VideoCaptureImpl::Create(
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000030 const int32_t id,
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000031 VideoCaptureExternal*& externalCapture)
32{
33 RefCountImpl<VideoCaptureImpl>* implementation =
34 new RefCountImpl<VideoCaptureImpl>(id);
niklase@google.com470e71d2011-07-07 08:21:25 +000035 externalCapture = implementation;
36 return implementation;
37}
38
leozwang@webrtc.org1745e932012-03-01 16:30:40 +000039const char* VideoCaptureImpl::CurrentDeviceName() const
niklase@google.com470e71d2011-07-07 08:21:25 +000040{
41 return _deviceUniqueId;
42}
43
fischman@webrtc.org4e65e072013-10-03 18:23:13 +000044// 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
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000085int32_t VideoCaptureImpl::ChangeUniqueId(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +000086{
87 _id = id;
88 return 0;
89}
90
91// returns the number of milliseconds until the module want a worker thread to call Process
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000092int64_t VideoCaptureImpl::TimeUntilNextProcess()
niklase@google.com470e71d2011-07-07 08:21:25 +000093{
perkj@webrtc.orgc2fde802012-08-08 14:01:09 +000094 CriticalSectionScoped cs(&_callBackCs);
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +000095 const int64_t kProcessIntervalMs = 300;
96 return kProcessIntervalMs -
97 (TickTime::Now() - _lastProcessTime).Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +000098}
99
100// Process any pending tasks such as timeouts
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000101int32_t VideoCaptureImpl::Process()
niklase@google.com470e71d2011-07-07 08:21:25 +0000102{
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000103 CriticalSectionScoped cs(&_callBackCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000104
105 const TickTime now = TickTime::Now();
106 _lastProcessTime = TickTime::Now();
107
108 // Handle No picture alarm
109
110 if (_lastProcessFrameCount.Ticks() == _incomingFrameTimes[0].Ticks() &&
111 _captureAlarm != Raised)
112 {
113 if (_noPictureAlarmCallBack && _captureCallBack)
114 {
115 _captureAlarm = Raised;
116 _captureCallBack->OnNoPictureAlarm(_id, _captureAlarm);
117 }
118 }
119 else if (_lastProcessFrameCount.Ticks() != _incomingFrameTimes[0].Ticks() &&
120 _captureAlarm != Cleared)
121 {
122 if (_noPictureAlarmCallBack && _captureCallBack)
123 {
124 _captureAlarm = Cleared;
125 _captureCallBack->OnNoPictureAlarm(_id, _captureAlarm);
126
127 }
128 }
129
130 // Handle frame rate callback
131 if ((now - _lastFrameRateCallbackTime).Milliseconds()
132 > kFrameRateCallbackInterval)
133 {
134 if (_frameRateCallBack && _captureCallBack)
135 {
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000136 const uint32_t frameRate = CalculateFrameRate(now);
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 _captureCallBack->OnCaptureFrameRate(_id, frameRate);
138 }
139 _lastFrameRateCallbackTime = now; // Can be set by EnableFrameRateCallback
140
141 }
142
143 _lastProcessFrameCount = _incomingFrameTimes[0];
144
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 return 0;
146}
147
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000148VideoCaptureImpl::VideoCaptureImpl(const int32_t id)
pbos@webrtc.org504af452013-07-02 10:15:43 +0000149 : _id(id),
150 _deviceUniqueId(NULL),
151 _apiCs(*CriticalSectionWrapper::CreateCriticalSection()),
152 _captureDelay(0),
153 _requestedCapability(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000154 _callBackCs(*CriticalSectionWrapper::CreateCriticalSection()),
155 _lastProcessTime(TickTime::Now()),
pbos@webrtc.org504af452013-07-02 10:15:43 +0000156 _lastFrameRateCallbackTime(TickTime::Now()),
157 _frameRateCallBack(false),
158 _noPictureAlarmCallBack(false),
159 _captureAlarm(Cleared),
160 _setCaptureDelay(0),
161 _dataCallBack(NULL),
162 _captureCallBack(NULL),
163 _lastProcessFrameCount(TickTime::Now()),
164 _rotateFrame(kRotateNone),
pbos@webrtc.orge0536292013-10-21 09:02:30 +0000165 last_capture_time_(0),
pbos@webrtc.org504af452013-07-02 10:15:43 +0000166 delta_ntp_internal_ms_(
167 Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() -
168 TickTime::MillisecondTimestamp()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000169 _requestedCapability.width = kDefaultWidth;
170 _requestedCapability.height = kDefaultHeight;
171 _requestedCapability.maxFPS = 30;
172 _requestedCapability.rawType = kVideoI420;
173 _requestedCapability.codecType = kVideoCodecUnknown;
174 memset(_incomingFrameTimes, 0, sizeof(_incomingFrameTimes));
175}
176
177VideoCaptureImpl::~VideoCaptureImpl()
178{
179 DeRegisterCaptureDataCallback();
180 DeRegisterCaptureCallback();
181 delete &_callBackCs;
182 delete &_apiCs;
183
184 if (_deviceUniqueId)
185 delete[] _deviceUniqueId;
186}
187
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000188void VideoCaptureImpl::RegisterCaptureDataCallback(
189 VideoCaptureDataCallback& dataCallBack) {
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000190 CriticalSectionScoped cs(&_apiCs);
191 CriticalSectionScoped cs2(&_callBackCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 _dataCallBack = &dataCallBack;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193}
194
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000195void VideoCaptureImpl::DeRegisterCaptureDataCallback() {
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000196 CriticalSectionScoped cs(&_apiCs);
197 CriticalSectionScoped cs2(&_callBackCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 _dataCallBack = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000199}
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000200void VideoCaptureImpl::RegisterCaptureCallback(VideoCaptureFeedBack& callBack) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000201
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000202 CriticalSectionScoped cs(&_apiCs);
203 CriticalSectionScoped cs2(&_callBackCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000204 _captureCallBack = &callBack;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205}
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000206void VideoCaptureImpl::DeRegisterCaptureCallback() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000207
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000208 CriticalSectionScoped cs(&_apiCs);
209 CriticalSectionScoped cs2(&_callBackCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000210 _captureCallBack = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000211}
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000212void VideoCaptureImpl::SetCaptureDelay(int32_t delayMS) {
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000213 CriticalSectionScoped cs(&_apiCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 _captureDelay = delayMS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000215}
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000216int32_t VideoCaptureImpl::CaptureDelay()
niklase@google.com470e71d2011-07-07 08:21:25 +0000217{
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000218 CriticalSectionScoped cs(&_apiCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000219 return _setCaptureDelay;
220}
wu@webrtc.orgf10ea312011-10-14 17:16:04 +0000221
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000222int32_t VideoCaptureImpl::DeliverCapturedFrame(I420VideoFrame& captureFrame,
223 int64_t capture_time) {
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000224 UpdateFrameCount(); // frame count used for local frame rate callback.
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000225
226 const bool callOnCaptureDelayChanged = _setCaptureDelay != _captureDelay;
227 // Capture delay changed
228 if (_setCaptureDelay != _captureDelay) {
229 _setCaptureDelay = _captureDelay;
230 }
231
232 // Set the capture time
233 if (capture_time != 0) {
andresp@webrtc.org77bf5c22013-09-04 11:35:43 +0000234 captureFrame.set_render_time_ms(capture_time - delta_ntp_internal_ms_);
pbos@webrtc.org504af452013-07-02 10:15:43 +0000235 } else {
236 captureFrame.set_render_time_ms(TickTime::MillisecondTimestamp());
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000237 }
238
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000239 if (captureFrame.render_time_ms() == last_capture_time_) {
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000240 // We don't allow the same capture time for two frames, drop this one.
241 return -1;
242 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000243 last_capture_time_ = captureFrame.render_time_ms();
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000244
245 if (_dataCallBack) {
246 if (callOnCaptureDelayChanged) {
247 _dataCallBack->OnCaptureDelayChanged(_id, _captureDelay);
248 }
mikhal@webrtc.orge83d3112012-10-29 15:59:40 +0000249 _dataCallBack->OnIncomingCapturedFrame(_id, captureFrame);
mikhal@webrtc.org80f14d22012-10-11 15:03:53 +0000250 }
251
252 return 0;
253}
254
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000255int32_t VideoCaptureImpl::IncomingFrame(
256 uint8_t* videoFrame,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000257 size_t videoFrameLength,
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000258 const VideoCaptureCapability& frameInfo,
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000259 int64_t captureTime/*=0*/)
niklase@google.com470e71d2011-07-07 08:21:25 +0000260{
fischman@webrtc.org42694c52014-06-06 18:28:28 +0000261 CriticalSectionScoped cs(&_apiCs);
262 CriticalSectionScoped cs2(&_callBackCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000263
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000264 const int32_t width = frameInfo.width;
265 const int32_t height = frameInfo.height;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
hclam@chromium.org806dc3b2013-04-09 19:54:10 +0000267 TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime);
268
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000269 if (frameInfo.codecType == kVideoCodecUnknown)
niklase@google.com470e71d2011-07-07 08:21:25 +0000270 {
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000271 // Not encoded, convert to I420.
mikhal@webrtc.orge39de162011-12-27 23:45:30 +0000272 const VideoType commonVideoType =
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000273 RawVideoTypeToCommonVideoVideoType(frameInfo.rawType);
274
275 if (frameInfo.rawType != kVideoMJPEG &&
elham@webrtc.org5f49dba2012-04-23 21:24:02 +0000276 CalcBufferSize(commonVideoType, width,
277 abs(height)) != videoFrameLength)
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 {
pbos@webrtc.org3d5cb332014-05-14 08:42:07 +0000279 LOG(LS_ERROR) << "Wrong incoming frame length.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 return -1;
281 }
282
mikhal@webrtc.org4c4d01d2012-11-21 22:18:32 +0000283 int stride_y = width;
284 int stride_uv = (width + 1) / 2;
mikhal@webrtc.org0f34fd72012-11-19 21:15:35 +0000285 int target_width = width;
286 int target_height = height;
287 // Rotating resolution when for 90/270 degree rotations.
288 if (_rotateFrame == kRotate90 || _rotateFrame == kRotate270) {
289 target_width = abs(height);
290 target_height = width;
291 }
mikhal@webrtc.org4c4d01d2012-11-21 22:18:32 +0000292 // TODO(mikhal): Update correct aligned stride values.
293 //Calc16ByteAlignedStride(target_width, &stride_y, &stride_uv);
mikhal@webrtc.org2f4ff892012-09-24 21:09:54 +0000294 // Setting absolute height (in case it was negative).
295 // In Windows, the image starts bottom left, instead of top left.
296 // Setting a negative source height, inverts the image (within LibYuv).
sheu@chromium.org5dd2ecb2013-10-31 23:41:04 +0000297 int ret = _captureFrame.CreateEmptyFrame(target_width,
298 abs(target_height),
299 stride_y,
300 stride_uv, stride_uv);
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000301 if (ret < 0)
302 {
pbos@webrtc.org3d5cb332014-05-14 08:42:07 +0000303 LOG(LS_ERROR) << "Failed to create empty frame, this should only "
304 "happen due to bad parameters.";
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000305 return -1;
306 }
mikhal@webrtc.orga58888d2012-01-04 19:23:24 +0000307 const int conversionResult = ConvertToI420(commonVideoType,
308 videoFrame,
309 0, 0, // No cropping
310 width, height,
mflodman@webrtc.orgf3811192012-02-27 08:10:17 +0000311 videoFrameLength,
mikhal@webrtc.orga58888d2012-01-04 19:23:24 +0000312 _rotateFrame,
sheu@chromium.org5dd2ecb2013-10-31 23:41:04 +0000313 &_captureFrame);
mikhal@webrtc.org2ab104e2011-12-09 02:46:22 +0000314 if (conversionResult < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000315 {
pbos@webrtc.org3d5cb332014-05-14 08:42:07 +0000316 LOG(LS_ERROR) << "Failed to convert capture frame from type "
317 << frameInfo.rawType << "to I420.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000318 return -1;
319 }
sheu@chromium.org5dd2ecb2013-10-31 23:41:04 +0000320 DeliverCapturedFrame(_captureFrame, captureTime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 }
322 else // Encoded format
323 {
mflodman@webrtc.org3ba883f2013-06-07 13:57:57 +0000324 assert(false);
325 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 }
327
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 return 0;
wu@webrtc.orgf10ea312011-10-14 17:16:04 +0000329}
niklase@google.com470e71d2011-07-07 08:21:25 +0000330
pbos@webrtc.org2ffb1492013-11-22 13:10:13 +0000331int32_t VideoCaptureImpl::IncomingI420VideoFrame(I420VideoFrame* video_frame,
332 int64_t captureTime) {
wu@webrtc.orgf10ea312011-10-14 17:16:04 +0000333
fischman@webrtc.org42694c52014-06-06 18:28:28 +0000334 CriticalSectionScoped cs(&_apiCs);
335 CriticalSectionScoped cs2(&_callBackCs);
pbos@webrtc.org2ffb1492013-11-22 13:10:13 +0000336 DeliverCapturedFrame(*video_frame, captureTime);
wu@webrtc.orgf10ea312011-10-14 17:16:04 +0000337
338 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000339}
340
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000341int32_t VideoCaptureImpl::SetCaptureRotation(VideoCaptureRotation rotation) {
mikhal@webrtc.org0f34fd72012-11-19 21:15:35 +0000342 CriticalSectionScoped cs(&_apiCs);
343 CriticalSectionScoped cs2(&_callBackCs);
344 switch (rotation){
345 case kCameraRotate0:
346 _rotateFrame = kRotateNone;
347 break;
348 case kCameraRotate90:
349 _rotateFrame = kRotate90;
350 break;
351 case kCameraRotate180:
352 _rotateFrame = kRotate180;
353 break;
354 case kCameraRotate270:
355 _rotateFrame = kRotate270;
356 break;
fischman@webrtc.org4e65e072013-10-03 18:23:13 +0000357 default:
358 return -1;
mikhal@webrtc.org0f34fd72012-11-19 21:15:35 +0000359 }
360 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000361}
362
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000363void VideoCaptureImpl::EnableFrameRateCallback(const bool enable) {
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000364 CriticalSectionScoped cs(&_apiCs);
365 CriticalSectionScoped cs2(&_callBackCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000366 _frameRateCallBack = enable;
367 if (enable)
368 {
369 _lastFrameRateCallbackTime = TickTime::Now();
370 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000371}
372
mallinath@webrtc.org7433a082014-01-29 00:56:02 +0000373void VideoCaptureImpl::EnableNoPictureAlarm(const bool enable) {
mflodman@webrtc.org7845d072012-03-08 08:09:17 +0000374 CriticalSectionScoped cs(&_apiCs);
375 CriticalSectionScoped cs2(&_callBackCs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 _noPictureAlarmCallBack = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +0000377}
378
379void VideoCaptureImpl::UpdateFrameCount()
380{
381 if (_incomingFrameTimes[0].MicrosecondTimestamp() == 0)
382 {
383 // first no shift
384 }
385 else
386 {
387 // shift
388 for (int i = (kFrameRateCountHistorySize - 2); i >= 0; i--)
389 {
390 _incomingFrameTimes[i + 1] = _incomingFrameTimes[i];
391 }
392 }
393 _incomingFrameTimes[0] = TickTime::Now();
394}
395
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000396uint32_t VideoCaptureImpl::CalculateFrameRate(const TickTime& now)
niklase@google.com470e71d2011-07-07 08:21:25 +0000397{
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000398 int32_t num = 0;
399 int32_t nrOfFrames = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 for (num = 1; num < (kFrameRateCountHistorySize - 1); num++)
401 {
402 if (_incomingFrameTimes[num].Ticks() <= 0
403 || (now - _incomingFrameTimes[num]).Milliseconds() > kFrameRateHistoryWindowMs) // don't use data older than 2sec
404 {
405 break;
406 }
407 else
408 {
409 nrOfFrames++;
410 }
411 }
412 if (num > 1)
413 {
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000414 int64_t diff = (now - _incomingFrameTimes[num - 1]).Milliseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +0000415 if (diff > 0)
416 {
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000417 return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f);
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 }
419 }
420
421 return nrOfFrames;
422}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000423} // namespace videocapturemodule
424} // namespace webrtc