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