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 {
Create(const int32_t id,VideoCaptureExternal * & externalCapture)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
CurrentDeviceName() const39 const char* VideoCaptureImpl::CurrentDeviceName() const
40 {
41 return _deviceUniqueId;
42 }
43
44 // static
RotationFromDegrees(int degrees,VideoCaptureRotation * rotation)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
RotationInDegrees(VideoCaptureRotation rotation,int * degrees)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
ChangeUniqueId(const int32_t id)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
TimeUntilNextProcess()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
Process()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
VideoCaptureImpl(const int32_t id)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
~VideoCaptureImpl()179 VideoCaptureImpl::~VideoCaptureImpl()
180 {
181 DeRegisterCaptureDataCallback();
182 DeRegisterCaptureCallback();
183 delete &_callBackCs;
184 delete &_apiCs;
185
186 if (_deviceUniqueId)
187 delete[] _deviceUniqueId;
188 }
189
RegisterCaptureDataCallback(VideoCaptureDataCallback & dataCallBack)190 void VideoCaptureImpl::RegisterCaptureDataCallback(
191 VideoCaptureDataCallback& dataCallBack) {
192 CriticalSectionScoped cs(&_apiCs);
193 CriticalSectionScoped cs2(&_callBackCs);
194 _dataCallBack = &dataCallBack;
195 }
196
DeRegisterCaptureDataCallback()197 void VideoCaptureImpl::DeRegisterCaptureDataCallback() {
198 CriticalSectionScoped cs(&_apiCs);
199 CriticalSectionScoped cs2(&_callBackCs);
200 _dataCallBack = NULL;
201 }
RegisterCaptureCallback(VideoCaptureFeedBack & callBack)202 void VideoCaptureImpl::RegisterCaptureCallback(VideoCaptureFeedBack& callBack) {
203
204 CriticalSectionScoped cs(&_apiCs);
205 CriticalSectionScoped cs2(&_callBackCs);
206 _captureCallBack = &callBack;
207 }
DeRegisterCaptureCallback()208 void VideoCaptureImpl::DeRegisterCaptureCallback() {
209
210 CriticalSectionScoped cs(&_apiCs);
211 CriticalSectionScoped cs2(&_callBackCs);
212 _captureCallBack = NULL;
213 }
SetCaptureDelay(int32_t delayMS)214 void VideoCaptureImpl::SetCaptureDelay(int32_t delayMS) {
215 CriticalSectionScoped cs(&_apiCs);
216 _captureDelay = delayMS;
217 }
CaptureDelay()218 int32_t VideoCaptureImpl::CaptureDelay()
219 {
220 CriticalSectionScoped cs(&_apiCs);
221 return _setCaptureDelay;
222 }
223
DeliverCapturedFrame(I420VideoFrame & captureFrame,int64_t capture_time)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
IncomingFrame(uint8_t * videoFrame,int32_t videoFrameLength,const VideoCaptureCapability & frameInfo,int64_t captureTime)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
IncomingI420VideoFrame(I420VideoFrame * video_frame,int64_t captureTime)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
SetCaptureRotation(VideoCaptureRotation rotation)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
EnableFrameRateCallback(const bool enable)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
EnableNoPictureAlarm(const bool enable)375 void VideoCaptureImpl::EnableNoPictureAlarm(const bool enable) {
376 CriticalSectionScoped cs(&_apiCs);
377 CriticalSectionScoped cs2(&_callBackCs);
378 _noPictureAlarmCallBack = enable;
379 }
380
UpdateFrameCount()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
CalculateFrameRate(const TickTime & now)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