1 /*
2  *  Copyright (c) 2014 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 #include <string>
15 
16 #include "webrtc/common_video/libyuv/include/scaler.h"
17 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
18 #include "webrtc/modules/interface/module_common_types.h"
19 #include "webrtc/modules/video_capture/video_capture_config.h"
20 #include "webrtc/system_wrappers/interface/clock.h"
21 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
22 #include "webrtc/system_wrappers/interface/ref_count.h"
23 #include "webrtc/system_wrappers/interface/tick_util.h"
24 #include "webrtc/system_wrappers/interface/trace.h"
25 #include "webrtc/system_wrappers/interface/trace_event.h"
26 #include "webrtc/video_engine/desktop_capture_impl.h"
27 #include "webrtc/modules/desktop_capture/desktop_frame.h"
28 #include "webrtc/modules/desktop_capture/desktop_device_info.h"
29 #include "webrtc/modules/desktop_capture/app_capturer.h"
30 #include "webrtc/modules/desktop_capture/window_capturer.h"
31 #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
32 
33 namespace webrtc {
34 
ScreenDeviceInfoImpl(const int32_t id)35 ScreenDeviceInfoImpl::ScreenDeviceInfoImpl(const int32_t id) : _id(id) {
36 }
37 
~ScreenDeviceInfoImpl(void)38 ScreenDeviceInfoImpl::~ScreenDeviceInfoImpl(void) {
39 }
40 
Init()41 int32_t ScreenDeviceInfoImpl::Init() {
42   desktop_device_info_.reset(DesktopDeviceInfoImpl::Create());
43   return 0;
44 }
45 
Refresh()46 int32_t ScreenDeviceInfoImpl::Refresh() {
47   desktop_device_info_->Refresh();
48   return 0;
49 }
50 
NumberOfDevices()51 uint32_t ScreenDeviceInfoImpl::NumberOfDevices() {
52   return desktop_device_info_->getDisplayDeviceCount();
53 }
54 
GetDeviceName(uint32_t deviceNumber,char * deviceNameUTF8,uint32_t deviceNameUTF8Length,char * deviceUniqueIdUTF8,uint32_t deviceUniqueIdUTF8Length,char * productUniqueIdUTF8,uint32_t productUniqueIdUTF8Length,pid_t * pid)55 int32_t ScreenDeviceInfoImpl::GetDeviceName(uint32_t deviceNumber,
56                                             char* deviceNameUTF8,
57                                             uint32_t deviceNameUTF8Length,
58                                             char* deviceUniqueIdUTF8,
59                                             uint32_t deviceUniqueIdUTF8Length,
60                                             char* productUniqueIdUTF8,
61                                             uint32_t productUniqueIdUTF8Length,
62                                             pid_t* pid) {
63 
64   DesktopDisplayDevice desktopDisplayDevice;
65 
66   // always initialize output
67   if (deviceNameUTF8 && deviceNameUTF8Length > 0) {
68     memset(deviceNameUTF8, 0, deviceNameUTF8Length);
69   }
70 
71   if (deviceUniqueIdUTF8 && deviceUniqueIdUTF8Length > 0) {
72     memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
73   }
74   if (productUniqueIdUTF8 && productUniqueIdUTF8Length > 0) {
75     memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
76   }
77 
78   if (desktop_device_info_->getDesktopDisplayDeviceInfo(deviceNumber,
79                                                        desktopDisplayDevice) == 0) {
80     size_t len;
81 
82     const char *deviceName = desktopDisplayDevice.getDeviceName();
83     len = deviceName ? strlen(deviceName) : 0;
84     if (len && deviceNameUTF8 && len <= deviceNameUTF8Length) {
85       memcpy(deviceNameUTF8,
86              deviceName,
87              len);
88     }
89 
90     const char *deviceUniqueId = desktopDisplayDevice.getUniqueIdName();
91     len = deviceUniqueId ? strlen(deviceUniqueId) : 0;
92     if (len && deviceUniqueIdUTF8 && len <= deviceUniqueIdUTF8Length) {
93       memcpy(deviceUniqueIdUTF8,
94              deviceUniqueId,
95              len);
96     }
97   }
98 
99   return 0;
100 }
101 
DisplayCaptureSettingsDialogBox(const char * deviceUniqueIdUTF8,const char * dialogTitleUTF8,void * parentWindow,uint32_t positionX,uint32_t positionY)102 int32_t ScreenDeviceInfoImpl::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
103                                                               const char* dialogTitleUTF8,
104                                                               void* parentWindow,
105                                                               uint32_t positionX,
106                                                               uint32_t positionY) {
107   // no device properties to change
108   return 0;
109 }
110 
NumberOfCapabilities(const char * deviceUniqueIdUTF8)111 int32_t ScreenDeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
112   return 0;
113 }
114 
GetCapability(const char * deviceUniqueIdUTF8,const uint32_t deviceCapabilityNumber,VideoCaptureCapability & capability)115 int32_t ScreenDeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
116                                             const uint32_t deviceCapabilityNumber,
117                                             VideoCaptureCapability& capability) {
118   return 0;
119 }
120 
GetBestMatchedCapability(const char * deviceUniqueIdUTF8,const VideoCaptureCapability & requested,VideoCaptureCapability & resulting)121 int32_t ScreenDeviceInfoImpl::GetBestMatchedCapability(const char* deviceUniqueIdUTF8,
122                                                        const VideoCaptureCapability& requested,
123                                                        VideoCaptureCapability& resulting) {
124   return 0;
125 }
126 
GetOrientation(const char * deviceUniqueIdUTF8,VideoRotation & orientation)127 int32_t ScreenDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
128                                              VideoRotation& orientation) {
129   return 0;
130 }
131 
AppDeviceInfoImpl(const int32_t id)132 AppDeviceInfoImpl::AppDeviceInfoImpl(const int32_t id) {
133 }
134 
~AppDeviceInfoImpl(void)135 AppDeviceInfoImpl::~AppDeviceInfoImpl(void) {
136 }
137 
Init()138 int32_t AppDeviceInfoImpl::Init() {
139   desktop_device_info_.reset(DesktopDeviceInfoImpl::Create());
140   return 0;
141 }
142 
Refresh()143 int32_t AppDeviceInfoImpl::Refresh() {
144   desktop_device_info_->Refresh();
145   return 0;
146 }
147 
NumberOfDevices()148 uint32_t AppDeviceInfoImpl::NumberOfDevices() {
149   return desktop_device_info_->getApplicationCount();
150 }
151 
GetDeviceName(uint32_t deviceNumber,char * deviceNameUTF8,uint32_t deviceNameUTF8Length,char * deviceUniqueIdUTF8,uint32_t deviceUniqueIdUTF8Length,char * productUniqueIdUTF8,uint32_t productUniqueIdUTF8Length,pid_t * pid)152 int32_t AppDeviceInfoImpl::GetDeviceName(uint32_t deviceNumber,
153                                          char* deviceNameUTF8,
154                                          uint32_t deviceNameUTF8Length,
155                                          char* deviceUniqueIdUTF8,
156                                          uint32_t deviceUniqueIdUTF8Length,
157                                          char* productUniqueIdUTF8,
158                                          uint32_t productUniqueIdUTF8Length,
159                                          pid_t* pid) {
160 
161   DesktopApplication desktopApplication;
162 
163   // always initialize output
164   if (deviceNameUTF8Length && deviceNameUTF8Length > 0) {
165     memset(deviceNameUTF8, 0, deviceNameUTF8Length);
166   }
167   if (deviceUniqueIdUTF8 && deviceUniqueIdUTF8Length > 0) {
168     memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
169   }
170   if (productUniqueIdUTF8 && productUniqueIdUTF8Length > 0) {
171     memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
172   }
173 
174   if (desktop_device_info_->getApplicationInfo(deviceNumber,desktopApplication) == 0) {
175     size_t len;
176 
177     const char *deviceName = desktopApplication.getProcessAppName();
178     len = deviceName ? strlen(deviceName) : 0;
179     if (len && len <= deviceNameUTF8Length) {
180       memcpy(deviceNameUTF8, deviceName, len);
181     }
182 
183     const char *deviceUniqueId = desktopApplication.getUniqueIdName();
184     len = deviceUniqueId ? strlen(deviceUniqueId) : 0;
185     if (len && deviceUniqueIdUTF8 && len <= deviceUniqueIdUTF8Length) {
186       memcpy(deviceUniqueIdUTF8,
187              deviceUniqueId,
188              len);
189     }
190     if (pid) {
191       *pid = desktopApplication.getProcessId();
192     }
193   }
194   return 0;
195 }
196 
DisplayCaptureSettingsDialogBox(const char * deviceUniqueIdUTF8,const char * dialogTitleUTF8,void * parentWindow,uint32_t positionX,uint32_t positionY)197 int32_t AppDeviceInfoImpl::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
198                                                            const char* dialogTitleUTF8,
199                                                            void* parentWindow,
200                                                            uint32_t positionX,
201                                                            uint32_t positionY) {
202   return 0;
203 }
204 
NumberOfCapabilities(const char * deviceUniqueIdUTF8)205 int32_t AppDeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
206   return 0;
207 }
208 
GetCapability(const char * deviceUniqueIdUTF8,const uint32_t deviceCapabilityNumber,VideoCaptureCapability & capability)209 int32_t AppDeviceInfoImpl::GetCapability(
210                                          const char* deviceUniqueIdUTF8,
211                                          const uint32_t deviceCapabilityNumber,
212                                          VideoCaptureCapability& capability) {
213   return 0;
214 }
215 
GetBestMatchedCapability(const char * deviceUniqueIdUTF8,const VideoCaptureCapability & requested,VideoCaptureCapability & resulting)216 int32_t AppDeviceInfoImpl::GetBestMatchedCapability(
217                                                     const char* deviceUniqueIdUTF8,
218                                                     const VideoCaptureCapability& requested,
219                                                     VideoCaptureCapability& resulting) {
220   return 0;
221 }
222 
GetOrientation(const char * deviceUniqueIdUTF8,VideoRotation & orientation)223 int32_t AppDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
224                                           VideoRotation& orientation) {
225   return 0;
226 }
227 
Create(const int32_t id,const char * uniqueId,const CaptureDeviceType type)228 VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t id,
229                                                const char* uniqueId,
230                                                const CaptureDeviceType type) {
231   RefCountImpl<DesktopCaptureImpl>* capture = new RefCountImpl<DesktopCaptureImpl>(id);
232 
233   //create real screen capturer.
234   if (capture->Init(uniqueId, type)) {
235     delete capture;
236     return NULL;
237   }
238 
239   return capture;
240 }
241 
Init()242 int32_t WindowDeviceInfoImpl::Init() {
243   desktop_device_info_.reset(DesktopDeviceInfoImpl::Create());
244   return 0;
245 }
246 
Refresh()247 int32_t WindowDeviceInfoImpl::Refresh() {
248   desktop_device_info_->Refresh();
249   return 0;
250 }
251 
NumberOfDevices()252 uint32_t WindowDeviceInfoImpl::NumberOfDevices() {
253   return desktop_device_info_->getWindowCount();
254 }
255 
GetDeviceName(uint32_t deviceNumber,char * deviceNameUTF8,uint32_t deviceNameUTF8Length,char * deviceUniqueIdUTF8,uint32_t deviceUniqueIdUTF8Length,char * productUniqueIdUTF8,uint32_t productUniqueIdUTF8Length,pid_t * pid)256 int32_t WindowDeviceInfoImpl::GetDeviceName(uint32_t deviceNumber,
257                                             char* deviceNameUTF8,
258                                             uint32_t deviceNameUTF8Length,
259                                             char* deviceUniqueIdUTF8,
260                                             uint32_t deviceUniqueIdUTF8Length,
261                                             char* productUniqueIdUTF8,
262                                             uint32_t productUniqueIdUTF8Length,
263                                             pid_t* pid) {
264 
265   DesktopDisplayDevice desktopDisplayDevice;
266 
267   // always initialize output
268   if (deviceNameUTF8 && deviceNameUTF8Length > 0) {
269     memset(deviceNameUTF8, 0, deviceNameUTF8Length);
270   }
271   if (deviceUniqueIdUTF8 && deviceUniqueIdUTF8Length > 0) {
272     memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
273   }
274   if (productUniqueIdUTF8 && productUniqueIdUTF8Length > 0) {
275     memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
276   }
277 
278   if (desktop_device_info_->getWindowInfo(deviceNumber,
279                                           desktopDisplayDevice) == 0) {
280 
281     size_t len;
282 
283     const char *deviceName = desktopDisplayDevice.getDeviceName();
284     len = deviceName ? strlen(deviceName) : 0;
285     if (len && deviceNameUTF8 && len <= deviceNameUTF8Length) {
286       memcpy(deviceNameUTF8,
287              deviceName,
288              len);
289     }
290 
291     const char *deviceUniqueId = desktopDisplayDevice.getUniqueIdName();
292     len = deviceUniqueId ? strlen(deviceUniqueId) : 0;
293     if (len && deviceUniqueIdUTF8 && len <= deviceUniqueIdUTF8Length) {
294       memcpy(deviceUniqueIdUTF8,
295              deviceUniqueId,
296              len);
297     }
298     if (pid) {
299       *pid = desktopDisplayDevice.getPid();
300     }
301   }
302 
303   return 0;
304 }
305 
DisplayCaptureSettingsDialogBox(const char * deviceUniqueIdUTF8,const char * dialogTitleUTF8,void * parentWindow,uint32_t positionX,uint32_t positionY)306 int32_t WindowDeviceInfoImpl::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
307                                                               const char* dialogTitleUTF8,
308                                                               void* parentWindow,
309                                                               uint32_t positionX,
310                                                               uint32_t positionY) {
311   // no device properties to change
312   return 0;
313 }
314 
NumberOfCapabilities(const char * deviceUniqueIdUTF8)315 int32_t WindowDeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
316   return 0;
317 }
318 
GetCapability(const char * deviceUniqueIdUTF8,const uint32_t deviceCapabilityNumber,VideoCaptureCapability & capability)319 int32_t WindowDeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
320                                             const uint32_t deviceCapabilityNumber,
321                                             VideoCaptureCapability& capability) {
322   return 0;
323 }
324 
GetBestMatchedCapability(const char * deviceUniqueIdUTF8,const VideoCaptureCapability & requested,VideoCaptureCapability & resulting)325 int32_t WindowDeviceInfoImpl::GetBestMatchedCapability(const char* deviceUniqueIdUTF8,
326                                                        const VideoCaptureCapability& requested,
327                                                        VideoCaptureCapability& resulting) {
328   return 0;
329 }
330 
GetOrientation(const char * deviceUniqueIdUTF8,VideoRotation & orientation)331 int32_t WindowDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
332                                              VideoRotation& orientation) {
333   return 0;
334 }
335 
CreateDeviceInfo(const int32_t id,const CaptureDeviceType type)336 VideoCaptureModule::DeviceInfo* DesktopCaptureImpl::CreateDeviceInfo(const int32_t id,
337                                                                      const CaptureDeviceType type) {
338   if (type == Application) {
339     AppDeviceInfoImpl * pAppDeviceInfoImpl = new AppDeviceInfoImpl(id);
340     if (!pAppDeviceInfoImpl || pAppDeviceInfoImpl->Init()) {
341       delete pAppDeviceInfoImpl;
342       pAppDeviceInfoImpl = NULL;
343     }
344     return pAppDeviceInfoImpl;
345   } else if (type == Screen) {
346     ScreenDeviceInfoImpl * pScreenDeviceInfoImpl = new ScreenDeviceInfoImpl(id);
347     if (!pScreenDeviceInfoImpl || pScreenDeviceInfoImpl->Init()) {
348       delete pScreenDeviceInfoImpl;
349       pScreenDeviceInfoImpl = NULL;
350     }
351     return pScreenDeviceInfoImpl;
352   } else if (type == Window) {
353     WindowDeviceInfoImpl * pWindowDeviceInfoImpl = new WindowDeviceInfoImpl(id);
354     if (!pWindowDeviceInfoImpl || pWindowDeviceInfoImpl->Init()) {
355       delete pWindowDeviceInfoImpl;
356       pWindowDeviceInfoImpl = NULL;
357     }
358     return pWindowDeviceInfoImpl;
359   }
360   return NULL;
361 }
362 
CurrentDeviceName() const363 const char* DesktopCaptureImpl::CurrentDeviceName() const {
364   return _deviceUniqueId.c_str();
365 }
366 
Init(const char * uniqueId,const CaptureDeviceType type)367 int32_t DesktopCaptureImpl::Init(const char* uniqueId,
368                                  const CaptureDeviceType type) {
369   DesktopCaptureOptions options = DesktopCaptureOptions::CreateDefault();
370   // Leave desktop effects enabled during WebRTC captures.
371   options.set_disable_effects(false);
372 
373   if (type == Application) {
374     AppCapturer *pAppCapturer = AppCapturer::Create(options);
375     if (!pAppCapturer) {
376       return -1;
377     }
378 
379     ProcessId pid = atoi(uniqueId);
380     pAppCapturer->SelectApp(pid);
381 
382     MouseCursorMonitor *pMouseCursorMonitor = MouseCursorMonitor::CreateForScreen(options, webrtc::kFullDesktopScreenId);
383     desktop_capturer_cursor_composer_.reset(new DesktopAndCursorComposer(pAppCapturer, pMouseCursorMonitor));
384   } else if (type == Screen) {
385     ScreenCapturer *pScreenCapturer = ScreenCapturer::Create(options);
386     if (!pScreenCapturer) {
387       return -1;
388     }
389 
390     ScreenId screenid = atoi(uniqueId);
391     pScreenCapturer->SelectScreen(screenid);
392     pScreenCapturer->SetMouseShapeObserver(this);
393 
394     MouseCursorMonitor *pMouseCursorMonitor = MouseCursorMonitor::CreateForScreen(options, screenid);
395     desktop_capturer_cursor_composer_.reset(new DesktopAndCursorComposer(pScreenCapturer, pMouseCursorMonitor));
396   } else if (type == Window) {
397     WindowCapturer *pWindowCapturer = WindowCapturer::Create();
398     if (!pWindowCapturer) {
399       return -1;
400     }
401 
402     WindowId winId = atoi(uniqueId);
403     pWindowCapturer->SelectWindow(winId);
404 
405     MouseCursorMonitor *pMouseCursorMonitor = MouseCursorMonitor::CreateForWindow(webrtc::DesktopCaptureOptions::CreateDefault(), winId);
406     desktop_capturer_cursor_composer_.reset(new DesktopAndCursorComposer(pWindowCapturer, pMouseCursorMonitor));
407   }
408   _deviceUniqueId = uniqueId;
409 
410   return 0;
411 }
412 
413 // returns the number of milliseconds until the module want a worker thread to call Process
TimeUntilNextProcess()414 int64_t DesktopCaptureImpl::TimeUntilNextProcess() {
415   CriticalSectionScoped cs(&_callBackCs);
416 
417   int64_t timeToNormalProcess = 300
418     - (int64_t)((TickTime::Now() - _lastProcessTime).Milliseconds());
419 
420   return timeToNormalProcess;
421 }
422 
423 // Process any pending tasks such as timeouts
Process()424 int32_t DesktopCaptureImpl::Process() {
425   CriticalSectionScoped cs(&_callBackCs);
426 
427   const TickTime now = TickTime::Now();
428   _lastProcessTime = TickTime::Now();
429 
430   // Handle No picture alarm
431   if (_lastProcessFrameCount.Ticks() == _incomingFrameTimes[0].Ticks() &&
432       _captureAlarm != Raised) {
433     if (_noPictureAlarmCallBack && _captureCallBack) {
434       _captureAlarm = Raised;
435       _captureCallBack->OnNoPictureAlarm(_id, _captureAlarm);
436     }
437   } else if (_lastProcessFrameCount.Ticks() != _incomingFrameTimes[0].Ticks() &&
438              _captureAlarm != Cleared) {
439     if (_noPictureAlarmCallBack && _captureCallBack) {
440       _captureAlarm = Cleared;
441       _captureCallBack->OnNoPictureAlarm(_id, _captureAlarm);
442     }
443   }
444 
445   // Handle frame rate callback
446   if ((now - _lastFrameRateCallbackTime).Milliseconds()
447       > kFrameRateCallbackInterval) {
448     if (_frameRateCallBack && _captureCallBack) {
449       const uint32_t frameRate = CalculateFrameRate(now);
450       _captureCallBack->OnCaptureFrameRate(_id, frameRate);
451     }
452     _lastFrameRateCallbackTime = now; // Can be set by EnableFrameRateCallback
453 
454   }
455 
456   _lastProcessFrameCount = _incomingFrameTimes[0];
457 
458   return 0;
459 }
460 
DesktopCaptureImpl(const int32_t id)461 DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id)
462   : _id(id),
463     _deviceUniqueId(""),
464     _apiCs(*CriticalSectionWrapper::CreateCriticalSection()),
465     _captureDelay(0),
466     _requestedCapability(),
467     _callBackCs(*CriticalSectionWrapper::CreateCriticalSection()),
468     _lastProcessTime(TickTime::Now()),
469     _lastFrameRateCallbackTime(TickTime::Now()),
470     _frameRateCallBack(false),
471     _noPictureAlarmCallBack(false),
472     _captureAlarm(Cleared),
473     _setCaptureDelay(0),
474     _dataCallBack(NULL),
475     _captureCallBack(NULL),
476     _lastProcessFrameCount(TickTime::Now()),
477     _rotateFrame(kVideoRotation_0),
478   last_capture_time_(TickTime::MillisecondTimestamp()),
479   delta_ntp_internal_ms_(
480                          Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() -
481                          TickTime::MillisecondTimestamp()),
482   time_event_(EventWrapper::Create()),
483 #if defined(_WIN32)
484   capturer_thread_(ThreadWrapper::CreateUIThread(Run, this, "ScreenCaptureThread")),
485 #else
486   capturer_thread_(ThreadWrapper::CreateThread(Run, this, "ScreenCaptureThread")),
487 #endif
488   started_(false) {
489   capturer_thread_->SetPriority(kHighPriority);
490   _requestedCapability.width = kDefaultWidth;
491   _requestedCapability.height = kDefaultHeight;
492   _requestedCapability.maxFPS = 30;
493   _requestedCapability.rawType = kVideoI420;
494   _requestedCapability.codecType = kVideoCodecUnknown;
495   memset(_incomingFrameTimes, 0, sizeof(_incomingFrameTimes));
496 }
497 
~DesktopCaptureImpl()498 DesktopCaptureImpl::~DesktopCaptureImpl() {
499   time_event_->Set();
500   capturer_thread_->Stop();
501 
502   DeRegisterCaptureDataCallback();
503   DeRegisterCaptureCallback();
504   delete &_callBackCs;
505   delete &_apiCs;
506 }
507 
RegisterCaptureDataCallback(VideoCaptureDataCallback & dataCallBack)508 void DesktopCaptureImpl::RegisterCaptureDataCallback(
509                                                      VideoCaptureDataCallback& dataCallBack)
510 {
511   CriticalSectionScoped cs(&_apiCs);
512   CriticalSectionScoped cs2(&_callBackCs);
513   _dataCallBack = &dataCallBack;
514 }
515 
DeRegisterCaptureDataCallback()516 void DesktopCaptureImpl::DeRegisterCaptureDataCallback()
517 {
518   CriticalSectionScoped cs(&_apiCs);
519   CriticalSectionScoped cs2(&_callBackCs);
520   _dataCallBack = NULL;
521 }
522 
RegisterCaptureCallback(VideoCaptureFeedBack & callBack)523 void DesktopCaptureImpl::RegisterCaptureCallback(VideoCaptureFeedBack& callBack)
524 {
525 
526   CriticalSectionScoped cs(&_apiCs);
527   CriticalSectionScoped cs2(&_callBackCs);
528   _captureCallBack = &callBack;
529 }
530 
DeRegisterCaptureCallback()531 void DesktopCaptureImpl::DeRegisterCaptureCallback()
532 {
533 
534   CriticalSectionScoped cs(&_apiCs);
535   CriticalSectionScoped cs2(&_callBackCs);
536   _captureCallBack = NULL;
537 }
538 
SetCaptureDelay(int32_t delayMS)539 void DesktopCaptureImpl::SetCaptureDelay(int32_t delayMS)
540 {
541   CriticalSectionScoped cs(&_apiCs);
542   _captureDelay = delayMS;
543 }
544 
CaptureDelay()545 int32_t DesktopCaptureImpl::CaptureDelay()
546 {
547   CriticalSectionScoped cs(&_apiCs);
548   return _setCaptureDelay;
549 }
550 
DeliverCapturedFrame(I420VideoFrame & captureFrame,int64_t capture_time)551 int32_t DesktopCaptureImpl::DeliverCapturedFrame(I420VideoFrame& captureFrame,
552                                                  int64_t capture_time) {
553   UpdateFrameCount();  // frame count used for local frame rate callback.
554 
555   const bool callOnCaptureDelayChanged = _setCaptureDelay != _captureDelay;
556   // Capture delay changed
557   if (_setCaptureDelay != _captureDelay) {
558     _setCaptureDelay = _captureDelay;
559   }
560 
561   // Set the capture time
562   if (capture_time != 0) {
563     captureFrame.set_render_time_ms(capture_time - delta_ntp_internal_ms_);
564   } else {
565     captureFrame.set_render_time_ms(TickTime::MillisecondTimestamp());
566   }
567 
568   if (captureFrame.render_time_ms() == last_capture_time_) {
569     // We don't allow the same capture time for two frames, drop this one.
570     return -1;
571   }
572   last_capture_time_ = captureFrame.render_time_ms();
573 
574   if (_dataCallBack) {
575     if (callOnCaptureDelayChanged) {
576       _dataCallBack->OnCaptureDelayChanged(_id, _captureDelay);
577     }
578     _dataCallBack->OnIncomingCapturedFrame(_id, captureFrame);
579   }
580 
581   return 0;
582 }
583 
584 // Copied from VideoCaptureImpl::IncomingFrame. See Bug 1038324
IncomingFrame(uint8_t * videoFrame,size_t videoFrameLength,const VideoCaptureCapability & frameInfo,int64_t captureTime)585 int32_t DesktopCaptureImpl::IncomingFrame(uint8_t* videoFrame,
586                                           size_t videoFrameLength,
587                                           const VideoCaptureCapability& frameInfo,
588                                           int64_t captureTime/*=0*/)
589 {
590   WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCapture, _id,
591                "IncomingFrame width %d, height %d", (int) frameInfo.width,
592                (int) frameInfo.height);
593 
594   TickTime startProcessTime = TickTime::Now();
595 
596   CriticalSectionScoped cs(&_callBackCs);
597 
598   const int32_t width = frameInfo.width;
599   const int32_t height = frameInfo.height;
600 
601   TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime);
602 
603   if (frameInfo.codecType == kVideoCodecUnknown) {
604     // Not encoded, convert to I420.
605     const VideoType commonVideoType =
606       RawVideoTypeToCommonVideoVideoType(frameInfo.rawType);
607 
608     if (frameInfo.rawType != kVideoMJPEG &&
609         CalcBufferSize(commonVideoType, width,
610                        abs(height)) != videoFrameLength) {
611       WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
612                    "Wrong incoming frame length.");
613       return -1;
614     }
615 
616     int stride_y = width;
617     int stride_uv = (width + 1) / 2;
618     int target_width = width;
619     int target_height = abs(height);
620     // Rotating resolution when for 90/270 degree rotations.
621     if (_rotateFrame == kVideoRotation_90 || _rotateFrame == kVideoRotation_270)  {
622       target_height = width;
623       target_width = abs(height);
624     }
625 
626     // Setting absolute height (in case it was negative).
627     // In Windows, the image starts bottom left, instead of top left.
628     // Setting a negative source height, inverts the image (within LibYuv).
629     int ret = _captureFrame.CreateEmptyFrame(target_width,
630                                              target_height,
631                                              stride_y,
632                                              stride_uv, stride_uv);
633     if (ret < 0) {
634       WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
635                    "Failed to allocate I420 frame.");
636       return -1;
637     }
638     const int conversionResult = ConvertToI420(commonVideoType,
639                                                videoFrame,
640                                                0, 0,  // No cropping
641                                                width, height,
642                                                videoFrameLength,
643                                                _rotateFrame,
644                                                &_captureFrame);
645     if (conversionResult < 0) {
646       WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
647                    "Failed to convert capture frame from type %d to I420",
648                    frameInfo.rawType);
649       return -1;
650     }
651 
652     int32_t req_max_width = _requestedCapability.width & 0xffff;
653     int32_t req_max_height = _requestedCapability.height & 0xffff;
654     int32_t req_ideal_width = (_requestedCapability.width >> 16) & 0xffff;
655     int32_t req_ideal_height = (_requestedCapability.height >> 16) & 0xffff;
656 
657     int32_t dest_max_width = std::min(req_max_width, target_width);
658     int32_t dest_max_height = std::min(req_max_height, target_height);
659     int32_t dst_width = std::min(req_ideal_width > 0 ? req_ideal_width : target_width, dest_max_width);
660     int32_t dst_height = std::min(req_ideal_height > 0 ? req_ideal_height : target_height, dest_max_height);
661 
662     // scale to average of portrait and landscape
663     float scale_width = (float)dst_width / (float)target_width;
664     float scale_height = (float)dst_height / (float)target_height;
665     float scale = (scale_width + scale_height) / 2;
666     dst_width = (int)(scale * target_width);
667     dst_height = (int)(scale * target_height);
668 
669     // if scaled rectangle exceeds max rectangle, scale to minimum of portrait and landscape
670     if (dst_width > dest_max_width || dst_height > dest_max_height) {
671       scale_width = (float)dest_max_width / (float)dst_width;
672       scale_height = (float)dest_max_height / (float)dst_height;
673       scale = std::min(scale_width, scale_height);
674       dst_width = (int)(scale * dst_width);
675       dst_height = (int)(scale * dst_height);
676     }
677 
678     if (dst_width == target_width && dst_height == target_height) {
679       DeliverCapturedFrame(_captureFrame, captureTime);
680     } else {
681 
682       I420VideoFrame scaledFrame;
683       ret = scaledFrame.CreateEmptyFrame(dst_width,
684                                          dst_height,
685                                          stride_y,
686                                          stride_uv, stride_uv);
687       if (ret < 0) {
688         WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
689                      "Failed to allocate I420 frame.");
690         return -1;
691       }
692 
693       webrtc::Scaler s;
694       s.Set(target_width, target_height, dst_width, dst_height, kI420, kI420, kScaleBox);
695       const int scaleResult = s.Scale(_captureFrame, &scaledFrame);
696 
697       if (scaleResult != 0) {
698         WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
699                      "Failed to scale capture frame from type %d",
700                      frameInfo.rawType);
701         return -1;
702       }
703 
704       DeliverCapturedFrame(scaledFrame, captureTime);
705     }
706 
707 
708 
709   } else {
710     assert(false);
711     return -1;
712   }
713 
714   const uint32_t processTime =
715     (uint32_t)(TickTime::Now() - startProcessTime).Milliseconds();
716 
717   if (processTime > 10) {
718     WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id,
719                  "Too long processing time of Incoming frame: %ums",
720                  (unsigned int) processTime);
721   }
722 
723   return 0;
724 }
725 
SetCaptureRotation(VideoRotation rotation)726 int32_t DesktopCaptureImpl::SetCaptureRotation(VideoRotation rotation) {
727   CriticalSectionScoped cs(&_apiCs);
728   CriticalSectionScoped cs2(&_callBackCs);
729   _rotateFrame = rotation;
730   return 0;
731 }
732 
SetApplyRotation(bool enable)733 bool DesktopCaptureImpl::SetApplyRotation(bool enable) {
734   return true;
735 }
736 
EnableFrameRateCallback(const bool enable)737 void DesktopCaptureImpl::EnableFrameRateCallback(const bool enable) {
738   CriticalSectionScoped cs(&_apiCs);
739   CriticalSectionScoped cs2(&_callBackCs);
740   _frameRateCallBack = enable;
741   if (enable) {
742     _lastFrameRateCallbackTime = TickTime::Now();
743   }
744 }
745 
EnableNoPictureAlarm(const bool enable)746 void DesktopCaptureImpl::EnableNoPictureAlarm(const bool enable) {
747   CriticalSectionScoped cs(&_apiCs);
748   CriticalSectionScoped cs2(&_callBackCs);
749   _noPictureAlarmCallBack = enable;
750 }
751 
UpdateFrameCount()752 void DesktopCaptureImpl::UpdateFrameCount() {
753   if (_incomingFrameTimes[0].MicrosecondTimestamp() == 0) {
754     // first no shift
755   } else {
756     // shift
757     for (int i = (kFrameRateCountHistorySize - 2); i >= 0; i--) {
758       _incomingFrameTimes[i + 1] = _incomingFrameTimes[i];
759     }
760   }
761   _incomingFrameTimes[0] = TickTime::Now();
762 }
763 
CalculateFrameRate(const TickTime & now)764 uint32_t DesktopCaptureImpl::CalculateFrameRate(const TickTime& now) {
765   int32_t num = 0;
766   int32_t nrOfFrames = 0;
767   for (num = 1; num < (kFrameRateCountHistorySize - 1); num++) {
768     // don't use data older than 2sec
769     if (_incomingFrameTimes[num].Ticks() <= 0
770         || (now - _incomingFrameTimes[num]).Milliseconds() > kFrameRateHistoryWindowMs) {
771       break;
772     } else {
773       nrOfFrames++;
774     }
775   }
776   if (num > 1) {
777     int64_t diff = (now - _incomingFrameTimes[num - 1]).Milliseconds();
778     if (diff > 0) {
779       // round to nearest value rather than return minimumid_
780       return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f);
781     }
782   }
783 
784   return nrOfFrames;
785 }
786 
StartCapture(const VideoCaptureCapability & capability)787 int32_t DesktopCaptureImpl::StartCapture(const VideoCaptureCapability& capability) {
788   _requestedCapability = capability;
789 #if defined(_WIN32)
790   uint32_t maxFPSNeeded = 1000/_requestedCapability.maxFPS;
791   capturer_thread_->RequestCallbackTimer(maxFPSNeeded);
792 #endif
793 
794   desktop_capturer_cursor_composer_->Start(this);
795   capturer_thread_->Start();
796   started_ = true;
797 
798   return 0;
799 }
800 
StopCapture()801 int32_t DesktopCaptureImpl::StopCapture() {
802   if (started_) {
803     capturer_thread_->Stop(); // thread is guaranteed stopped before this returns
804     desktop_capturer_cursor_composer_->Stop();
805     started_ = false;
806     return 0;
807   }
808   return -1;
809 }
810 
CaptureStarted()811 bool DesktopCaptureImpl::CaptureStarted() {
812   return started_;
813 }
814 
CaptureSettings(VideoCaptureCapability & settings)815 int32_t DesktopCaptureImpl::CaptureSettings(VideoCaptureCapability& settings) {
816   return -1;
817 }
818 
OnCaptureCompleted(DesktopFrame * frame)819 void DesktopCaptureImpl::OnCaptureCompleted(DesktopFrame* frame) {
820   if (frame == NULL) return;
821   uint8_t * videoFrame = frame->data();
822   VideoCaptureCapability frameInfo;
823   frameInfo.width = frame->size().width();
824   frameInfo.height = frame->size().height();
825   frameInfo.rawType = kVideoARGB;
826 
827   // combine cursor in frame
828   // Latest WebRTC already support it by DesktopFrameWithCursor/DesktopAndCursorComposer.
829 
830   size_t videoFrameLength = frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel;
831   IncomingFrame(videoFrame, videoFrameLength, frameInfo);
832   delete frame; //handled it, so we need delete it
833 }
834 
CreateSharedMemory(size_t size)835 SharedMemory* DesktopCaptureImpl::CreateSharedMemory(size_t size) {
836   return NULL;
837 }
838 
process()839 void DesktopCaptureImpl::process() {
840   DesktopRect desktop_rect;
841   DesktopRegion desktop_region;
842 
843 #if !defined(_WIN32)
844   TickTime startProcessTime = TickTime::Now();
845 #endif
846 
847   desktop_capturer_cursor_composer_->Capture(DesktopRegion());
848 
849 #if !defined(_WIN32)
850   const uint32_t processTime =
851       (uint32_t)(TickTime::Now() - startProcessTime).Milliseconds();
852   // Use at most x% CPU or limit framerate
853   const uint32_t maxFPSNeeded = 1000/_requestedCapability.maxFPS;
854   const float sleepTimeFactor = (100.0f / kMaxDesktopCaptureCpuUsage) - 1.0f;
855   const uint32_t sleepTime = sleepTimeFactor * processTime;
856   time_event_->Wait(std::max<uint32_t>(maxFPSNeeded, sleepTime));
857 #endif
858 }
859 
860 }  // namespace webrtc
861 
862