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 {
Create(const int32_t id,VideoCaptureExternal * & externalCapture)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
CurrentDeviceName() const40 const char* VideoCaptureImpl::CurrentDeviceName() const
41 {
42 return _deviceUniqueId;
43 }
44
45 // static
RotationFromDegrees(int degrees,VideoRotation * rotation)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
RotationInDegrees(VideoRotation rotation,int * degrees)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
TimeUntilNextProcess()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
Process()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
VideoCaptureImpl(const int32_t id)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
~VideoCaptureImpl()169 VideoCaptureImpl::~VideoCaptureImpl()
170 {
171 DeRegisterCaptureDataCallback();
172 DeRegisterCaptureCallback();
173 delete &_callBackCs;
174 delete &_apiCs;
175
176 if (_deviceUniqueId)
177 delete[] _deviceUniqueId;
178 }
179
RegisterCaptureDataCallback(VideoCaptureDataCallback & dataCallBack)180 void VideoCaptureImpl::RegisterCaptureDataCallback(
181 VideoCaptureDataCallback& dataCallBack) {
182 CriticalSectionScoped cs(&_apiCs);
183 CriticalSectionScoped cs2(&_callBackCs);
184 _dataCallBack = &dataCallBack;
185 }
186
DeRegisterCaptureDataCallback()187 void VideoCaptureImpl::DeRegisterCaptureDataCallback() {
188 CriticalSectionScoped cs(&_apiCs);
189 CriticalSectionScoped cs2(&_callBackCs);
190 _dataCallBack = NULL;
191 }
RegisterCaptureCallback(VideoCaptureFeedBack & callBack)192 void VideoCaptureImpl::RegisterCaptureCallback(VideoCaptureFeedBack& callBack) {
193
194 CriticalSectionScoped cs(&_apiCs);
195 CriticalSectionScoped cs2(&_callBackCs);
196 _captureCallBack = &callBack;
197 }
DeRegisterCaptureCallback()198 void VideoCaptureImpl::DeRegisterCaptureCallback() {
199
200 CriticalSectionScoped cs(&_apiCs);
201 CriticalSectionScoped cs2(&_callBackCs);
202 _captureCallBack = NULL;
203 }
SetCaptureDelay(int32_t delayMS)204 void VideoCaptureImpl::SetCaptureDelay(int32_t delayMS) {
205 CriticalSectionScoped cs(&_apiCs);
206 _captureDelay = delayMS;
207 }
CaptureDelay()208 int32_t VideoCaptureImpl::CaptureDelay()
209 {
210 CriticalSectionScoped cs(&_apiCs);
211 return _setCaptureDelay;
212 }
213
DeliverCapturedFrame(VideoFrame & captureFrame)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
IncomingFrame(uint8_t * videoFrame,size_t videoFrameLength,const VideoCaptureCapability & frameInfo,int64_t captureTime)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
SetCaptureRotation(VideoRotation rotation)323 int32_t VideoCaptureImpl::SetCaptureRotation(VideoRotation rotation) {
324 CriticalSectionScoped cs(&_apiCs);
325 CriticalSectionScoped cs2(&_callBackCs);
326 _rotateFrame = rotation;
327 return 0;
328 }
329
EnableFrameRateCallback(const bool enable)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
SetApplyRotation(bool enable)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
EnableNoPictureAlarm(const bool enable)348 void VideoCaptureImpl::EnableNoPictureAlarm(const bool enable) {
349 CriticalSectionScoped cs(&_apiCs);
350 CriticalSectionScoped cs2(&_callBackCs);
351 _noPictureAlarmCallBack = enable;
352 }
353
UpdateFrameCount()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
CalculateFrameRate(const TickTime & now)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