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