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 
28 namespace videocapturemodule
29 {
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 
40 const char* VideoCaptureImpl::CurrentDeviceName() const
41 {
42     return _deviceUniqueId;
43 }
44 
45 // static
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
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
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
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 
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 
169 VideoCaptureImpl::~VideoCaptureImpl()
170 {
171     DeRegisterCaptureDataCallback();
172     DeRegisterCaptureCallback();
173     delete &_callBackCs;
174     delete &_apiCs;
175 
176     if (_deviceUniqueId)
177         delete[] _deviceUniqueId;
178 }
179 
180 void VideoCaptureImpl::RegisterCaptureDataCallback(
181     VideoCaptureDataCallback& dataCallBack) {
182     CriticalSectionScoped cs(&_apiCs);
183     CriticalSectionScoped cs2(&_callBackCs);
184     _dataCallBack = &dataCallBack;
185 }
186 
187 void VideoCaptureImpl::DeRegisterCaptureDataCallback() {
188     CriticalSectionScoped cs(&_apiCs);
189     CriticalSectionScoped cs2(&_callBackCs);
190     _dataCallBack = NULL;
191 }
192 void VideoCaptureImpl::RegisterCaptureCallback(VideoCaptureFeedBack& callBack) {
193 
194     CriticalSectionScoped cs(&_apiCs);
195     CriticalSectionScoped cs2(&_callBackCs);
196     _captureCallBack = &callBack;
197 }
198 void VideoCaptureImpl::DeRegisterCaptureCallback() {
199 
200     CriticalSectionScoped cs(&_apiCs);
201     CriticalSectionScoped cs2(&_callBackCs);
202     _captureCallBack = NULL;
203 }
204 void VideoCaptureImpl::SetCaptureDelay(int32_t delayMS) {
205     CriticalSectionScoped cs(&_apiCs);
206     _captureDelay = delayMS;
207 }
208 int32_t VideoCaptureImpl::CaptureDelay()
209 {
210     CriticalSectionScoped cs(&_apiCs);
211     return _setCaptureDelay;
212 }
213 
214 int32_t VideoCaptureImpl::DeliverCapturedFrame(I420VideoFrame& 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 
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         // SetApplyRotation doesn't take any lock. Make a local copy here.
262         bool apply_rotation = apply_rotation_;
263         int target_width;
264         int target_height;
265 
266         if (apply_rotation &&
267             (_rotateFrame == kVideoRotation_90 ||
268              _rotateFrame == kVideoRotation_270)) {
269           target_width = abs(height);
270           target_height = width;
271         } else {
272           target_width = width;
273           target_height = height;
274         }
275 
276         int stride_y = target_width;
277         int stride_uv = (target_width + 1) / 2;
278 
279         // TODO(mikhal): Update correct aligned stride values.
280         //Calc16ByteAlignedStride(target_width, &stride_y, &stride_uv);
281         // Setting absolute height (in case it was negative).
282         // In Windows, the image starts bottom left, instead of top left.
283         // Setting a negative source height, inverts the image (within LibYuv).
284         int ret = _captureFrame.CreateEmptyFrame(target_width,
285                                                  abs(target_height),
286                                                  stride_y,
287                                                  stride_uv, stride_uv);
288         if (ret < 0)
289         {
290             LOG(LS_ERROR) << "Failed to create empty frame, this should only "
291                              "happen due to bad parameters.";
292             return -1;
293         }
294         const int conversionResult = ConvertToI420(
295             commonVideoType, videoFrame, 0, 0,  // No cropping
296             width, height, videoFrameLength,
297             apply_rotation ? _rotateFrame : kVideoRotation_0, &_captureFrame);
298         if (conversionResult != 0)
299         {
300           LOG(LS_ERROR) << "Failed to convert capture frame from type "
301                         << frameInfo.rawType << "to I420.";
302             return -1;
303         }
304 
305         if (!apply_rotation) {
306           _captureFrame.set_rotation(_rotateFrame);
307         } else {
308           _captureFrame.set_rotation(kVideoRotation_0);
309         }
310         _captureFrame.set_ntp_time_ms(captureTime);
311         _captureFrame.set_render_time_ms(TickTime::MillisecondTimestamp());
312 
313         DeliverCapturedFrame(_captureFrame);
314     }
315     else // Encoded format
316     {
317         assert(false);
318         return -1;
319     }
320 
321     return 0;
322 }
323 
324 int32_t VideoCaptureImpl::SetCaptureRotation(VideoRotation rotation) {
325   CriticalSectionScoped cs(&_apiCs);
326   CriticalSectionScoped cs2(&_callBackCs);
327   _rotateFrame = rotation;
328   return 0;
329 }
330 
331 void VideoCaptureImpl::EnableFrameRateCallback(const bool enable) {
332     CriticalSectionScoped cs(&_apiCs);
333     CriticalSectionScoped cs2(&_callBackCs);
334     _frameRateCallBack = enable;
335     if (enable)
336     {
337         _lastFrameRateCallbackTime = TickTime::Now();
338     }
339 }
340 
341 bool VideoCaptureImpl::SetApplyRotation(bool enable) {
342   // We can't take any lock here as it'll cause deadlock with IncomingFrame.
343 
344   // The effect of this is the last caller wins.
345   apply_rotation_ = enable;
346   return true;
347 }
348 
349 void VideoCaptureImpl::EnableNoPictureAlarm(const bool enable) {
350     CriticalSectionScoped cs(&_apiCs);
351     CriticalSectionScoped cs2(&_callBackCs);
352     _noPictureAlarmCallBack = enable;
353 }
354 
355 void VideoCaptureImpl::UpdateFrameCount()
356 {
357     if (_incomingFrameTimes[0].MicrosecondTimestamp() == 0)
358     {
359         // first no shift
360     }
361     else
362     {
363         // shift
364         for (int i = (kFrameRateCountHistorySize - 2); i >= 0; i--)
365         {
366             _incomingFrameTimes[i + 1] = _incomingFrameTimes[i];
367         }
368     }
369     _incomingFrameTimes[0] = TickTime::Now();
370 }
371 
372 uint32_t VideoCaptureImpl::CalculateFrameRate(const TickTime& now)
373 {
374     int32_t num = 0;
375     int32_t nrOfFrames = 0;
376     for (num = 1; num < (kFrameRateCountHistorySize - 1); num++)
377     {
378         if (_incomingFrameTimes[num].Ticks() <= 0
379             || (now - _incomingFrameTimes[num]).Milliseconds() > kFrameRateHistoryWindowMs) // don't use data older than 2sec
380         {
381             break;
382         }
383         else
384         {
385             nrOfFrames++;
386         }
387     }
388     if (num > 1)
389     {
390         int64_t diff = (now - _incomingFrameTimes[num - 1]).Milliseconds();
391         if (diff > 0)
392         {
393             return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f);
394         }
395     }
396 
397     return nrOfFrames;
398 }
399 }  // namespace videocapturemodule
400 }  // namespace webrtc
401