• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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