Line data Source code
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/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/trace.h"
22 : #include "webrtc/base/trace_event.h"
23 : #include "webrtc/video_engine/desktop_capture_impl.h"
24 : #include "webrtc/modules/desktop_capture/desktop_frame.h"
25 : #include "webrtc/modules/desktop_capture/desktop_device_info.h"
26 : #include "webrtc/modules/desktop_capture/app_capturer.h"
27 : #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
28 : #include "webrtc/modules/video_capture/video_capture.h"
29 :
30 : namespace webrtc {
31 :
32 0 : ScreenDeviceInfoImpl::ScreenDeviceInfoImpl(const int32_t id) : _id(id) {
33 0 : }
34 :
35 0 : ScreenDeviceInfoImpl::~ScreenDeviceInfoImpl(void) {
36 0 : }
37 :
38 0 : int32_t ScreenDeviceInfoImpl::Init() {
39 0 : desktop_device_info_ = std::unique_ptr<DesktopDeviceInfo>(DesktopDeviceInfoImpl::Create());
40 0 : return 0;
41 : }
42 :
43 0 : int32_t ScreenDeviceInfoImpl::Refresh() {
44 0 : desktop_device_info_->Refresh();
45 0 : return 0;
46 : }
47 :
48 0 : uint32_t ScreenDeviceInfoImpl::NumberOfDevices() {
49 0 : return desktop_device_info_->getDisplayDeviceCount();
50 : }
51 :
52 0 : int32_t ScreenDeviceInfoImpl::GetDeviceName(uint32_t deviceNumber,
53 : char* deviceNameUTF8,
54 : uint32_t deviceNameUTF8Length,
55 : char* deviceUniqueIdUTF8,
56 : uint32_t deviceUniqueIdUTF8Length,
57 : char* productUniqueIdUTF8,
58 : uint32_t productUniqueIdUTF8Length,
59 : pid_t* pid) {
60 :
61 0 : DesktopDisplayDevice desktopDisplayDevice;
62 :
63 : // always initialize output
64 0 : if (deviceNameUTF8 && deviceNameUTF8Length > 0) {
65 0 : memset(deviceNameUTF8, 0, deviceNameUTF8Length);
66 : }
67 :
68 0 : if (deviceUniqueIdUTF8 && deviceUniqueIdUTF8Length > 0) {
69 0 : memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
70 : }
71 0 : if (productUniqueIdUTF8 && productUniqueIdUTF8Length > 0) {
72 0 : memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
73 : }
74 :
75 0 : if (desktop_device_info_->getDesktopDisplayDeviceInfo(deviceNumber,
76 0 : desktopDisplayDevice) == 0) {
77 : size_t len;
78 :
79 0 : const char *deviceName = desktopDisplayDevice.getDeviceName();
80 0 : len = deviceName ? strlen(deviceName) : 0;
81 0 : if (len && deviceNameUTF8 && len <= deviceNameUTF8Length) {
82 : memcpy(deviceNameUTF8,
83 : deviceName,
84 0 : len);
85 : }
86 :
87 0 : const char *deviceUniqueId = desktopDisplayDevice.getUniqueIdName();
88 0 : len = deviceUniqueId ? strlen(deviceUniqueId) : 0;
89 0 : if (len && deviceUniqueIdUTF8 && len <= deviceUniqueIdUTF8Length) {
90 : memcpy(deviceUniqueIdUTF8,
91 : deviceUniqueId,
92 0 : len);
93 : }
94 : }
95 :
96 0 : return 0;
97 : }
98 :
99 0 : int32_t ScreenDeviceInfoImpl::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
100 : const char* dialogTitleUTF8,
101 : void* parentWindow,
102 : uint32_t positionX,
103 : uint32_t positionY) {
104 : // no device properties to change
105 0 : return 0;
106 : }
107 :
108 0 : int32_t ScreenDeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
109 0 : return 0;
110 : }
111 :
112 0 : int32_t ScreenDeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
113 : const uint32_t deviceCapabilityNumber,
114 : VideoCaptureCapability& capability) {
115 0 : return 0;
116 : }
117 :
118 0 : int32_t ScreenDeviceInfoImpl::GetBestMatchedCapability(const char* deviceUniqueIdUTF8,
119 : const VideoCaptureCapability& requested,
120 : VideoCaptureCapability& resulting) {
121 0 : return 0;
122 : }
123 :
124 0 : int32_t ScreenDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
125 : VideoRotation& orientation) {
126 0 : return 0;
127 : }
128 :
129 0 : AppDeviceInfoImpl::AppDeviceInfoImpl(const int32_t id) {
130 0 : }
131 :
132 0 : AppDeviceInfoImpl::~AppDeviceInfoImpl(void) {
133 0 : }
134 :
135 0 : int32_t AppDeviceInfoImpl::Init() {
136 0 : desktop_device_info_ = std::unique_ptr<DesktopDeviceInfo>(DesktopDeviceInfoImpl::Create());
137 0 : return 0;
138 : }
139 :
140 0 : int32_t AppDeviceInfoImpl::Refresh() {
141 0 : desktop_device_info_->Refresh();
142 0 : return 0;
143 : }
144 :
145 0 : uint32_t AppDeviceInfoImpl::NumberOfDevices() {
146 0 : return desktop_device_info_->getApplicationCount();
147 : }
148 :
149 0 : int32_t AppDeviceInfoImpl::GetDeviceName(uint32_t deviceNumber,
150 : char* deviceNameUTF8,
151 : uint32_t deviceNameUTF8Length,
152 : char* deviceUniqueIdUTF8,
153 : uint32_t deviceUniqueIdUTF8Length,
154 : char* productUniqueIdUTF8,
155 : uint32_t productUniqueIdUTF8Length,
156 : pid_t* pid) {
157 :
158 0 : DesktopApplication desktopApplication;
159 :
160 : // always initialize output
161 0 : if (deviceNameUTF8Length && deviceNameUTF8Length > 0) {
162 0 : memset(deviceNameUTF8, 0, deviceNameUTF8Length);
163 : }
164 0 : if (deviceUniqueIdUTF8 && deviceUniqueIdUTF8Length > 0) {
165 0 : memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
166 : }
167 0 : if (productUniqueIdUTF8 && productUniqueIdUTF8Length > 0) {
168 0 : memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
169 : }
170 :
171 0 : if (desktop_device_info_->getApplicationInfo(deviceNumber,desktopApplication) == 0) {
172 : size_t len;
173 :
174 0 : const char *deviceName = desktopApplication.getProcessAppName();
175 0 : len = deviceName ? strlen(deviceName) : 0;
176 0 : if (len && len <= deviceNameUTF8Length) {
177 0 : memcpy(deviceNameUTF8, deviceName, len);
178 : }
179 :
180 0 : const char *deviceUniqueId = desktopApplication.getUniqueIdName();
181 0 : len = deviceUniqueId ? strlen(deviceUniqueId) : 0;
182 0 : if (len && deviceUniqueIdUTF8 && len <= deviceUniqueIdUTF8Length) {
183 : memcpy(deviceUniqueIdUTF8,
184 : deviceUniqueId,
185 0 : len);
186 : }
187 0 : if (pid) {
188 0 : *pid = desktopApplication.getProcessId();
189 : }
190 : }
191 0 : return 0;
192 : }
193 :
194 0 : int32_t AppDeviceInfoImpl::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
195 : const char* dialogTitleUTF8,
196 : void* parentWindow,
197 : uint32_t positionX,
198 : uint32_t positionY) {
199 0 : return 0;
200 : }
201 :
202 0 : int32_t AppDeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
203 0 : return 0;
204 : }
205 :
206 0 : int32_t AppDeviceInfoImpl::GetCapability(
207 : const char* deviceUniqueIdUTF8,
208 : const uint32_t deviceCapabilityNumber,
209 : VideoCaptureCapability& capability) {
210 0 : return 0;
211 : }
212 :
213 0 : int32_t AppDeviceInfoImpl::GetBestMatchedCapability(
214 : const char* deviceUniqueIdUTF8,
215 : const VideoCaptureCapability& requested,
216 : VideoCaptureCapability& resulting) {
217 0 : return 0;
218 : }
219 :
220 0 : int32_t AppDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
221 : VideoRotation& orientation) {
222 0 : return 0;
223 : }
224 :
225 0 : VideoCaptureModule* DesktopCaptureImpl::Create(const int32_t id,
226 : const char* uniqueId,
227 : const CaptureDeviceType type) {
228 :
229 0 : rtc::RefCountedObject<DesktopCaptureImpl>* capture = new rtc::RefCountedObject<DesktopCaptureImpl>(id);
230 :
231 : //create real screen capturer.
232 0 : if (capture->Init(uniqueId, type)) {
233 0 : capture->Release();
234 0 : return nullptr;
235 : }
236 :
237 0 : return capture;
238 : }
239 :
240 0 : int32_t WindowDeviceInfoImpl::Init() {
241 0 : desktop_device_info_ = std::unique_ptr<DesktopDeviceInfo>(DesktopDeviceInfoImpl::Create());
242 0 : return 0;
243 : }
244 :
245 0 : int32_t DesktopCaptureImpl::AddRef() const {
246 0 : return ++mRefCount;
247 : }
248 0 : int32_t DesktopCaptureImpl::Release() const {
249 0 : assert(mRefCount > 0);
250 0 : auto count = --mRefCount;
251 0 : if (!count) {
252 : WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCapture, -1,
253 : "DesktopCapture self deleting (desktopCapture=0x%p)", this);
254 :
255 : // Clear any pointers before starting destruction. Otherwise worker-
256 : // threads will still have pointers to a partially destructed object.
257 : // Example: AudioDeviceBuffer::RequestPlayoutData() can access a
258 : // partially deconstructed |_ptrCbAudioTransport| during destruction
259 : // if we don't call Terminate here.
260 : //-> NG TODO Terminate();
261 0 : delete this;
262 0 : return count;
263 : }
264 0 : return mRefCount;
265 : }
266 :
267 0 : int32_t WindowDeviceInfoImpl::Refresh() {
268 0 : desktop_device_info_->Refresh();
269 0 : return 0;
270 : }
271 :
272 0 : uint32_t WindowDeviceInfoImpl::NumberOfDevices() {
273 0 : return desktop_device_info_->getWindowCount();
274 : }
275 :
276 0 : int32_t WindowDeviceInfoImpl::GetDeviceName(uint32_t deviceNumber,
277 : char* deviceNameUTF8,
278 : uint32_t deviceNameUTF8Length,
279 : char* deviceUniqueIdUTF8,
280 : uint32_t deviceUniqueIdUTF8Length,
281 : char* productUniqueIdUTF8,
282 : uint32_t productUniqueIdUTF8Length,
283 : pid_t* pid) {
284 :
285 0 : DesktopDisplayDevice desktopDisplayDevice;
286 :
287 : // always initialize output
288 0 : if (deviceNameUTF8 && deviceNameUTF8Length > 0) {
289 0 : memset(deviceNameUTF8, 0, deviceNameUTF8Length);
290 : }
291 0 : if (deviceUniqueIdUTF8 && deviceUniqueIdUTF8Length > 0) {
292 0 : memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
293 : }
294 0 : if (productUniqueIdUTF8 && productUniqueIdUTF8Length > 0) {
295 0 : memset(productUniqueIdUTF8, 0, productUniqueIdUTF8Length);
296 : }
297 :
298 0 : if (desktop_device_info_->getWindowInfo(deviceNumber,
299 0 : desktopDisplayDevice) == 0) {
300 :
301 : size_t len;
302 :
303 0 : const char *deviceName = desktopDisplayDevice.getDeviceName();
304 0 : len = deviceName ? strlen(deviceName) : 0;
305 0 : if (len && deviceNameUTF8 && len <= deviceNameUTF8Length) {
306 : memcpy(deviceNameUTF8,
307 : deviceName,
308 0 : len);
309 : }
310 :
311 0 : const char *deviceUniqueId = desktopDisplayDevice.getUniqueIdName();
312 0 : len = deviceUniqueId ? strlen(deviceUniqueId) : 0;
313 0 : if (len && deviceUniqueIdUTF8 && len <= deviceUniqueIdUTF8Length) {
314 : memcpy(deviceUniqueIdUTF8,
315 : deviceUniqueId,
316 0 : len);
317 : }
318 0 : if (pid) {
319 0 : *pid = desktopDisplayDevice.getPid();
320 : }
321 : }
322 :
323 0 : return 0;
324 : }
325 :
326 0 : int32_t WindowDeviceInfoImpl::DisplayCaptureSettingsDialogBox(const char* deviceUniqueIdUTF8,
327 : const char* dialogTitleUTF8,
328 : void* parentWindow,
329 : uint32_t positionX,
330 : uint32_t positionY) {
331 : // no device properties to change
332 0 : return 0;
333 : }
334 :
335 0 : int32_t WindowDeviceInfoImpl::NumberOfCapabilities(const char* deviceUniqueIdUTF8) {
336 0 : return 0;
337 : }
338 :
339 0 : int32_t WindowDeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8,
340 : const uint32_t deviceCapabilityNumber,
341 : VideoCaptureCapability& capability) {
342 0 : return 0;
343 : }
344 :
345 0 : int32_t WindowDeviceInfoImpl::GetBestMatchedCapability(const char* deviceUniqueIdUTF8,
346 : const VideoCaptureCapability& requested,
347 : VideoCaptureCapability& resulting) {
348 0 : return 0;
349 : }
350 :
351 0 : int32_t WindowDeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
352 : VideoRotation& orientation) {
353 0 : return 0;
354 : }
355 :
356 0 : VideoCaptureModule::DeviceInfo* DesktopCaptureImpl::CreateDeviceInfo(const int32_t id,
357 : const CaptureDeviceType type) {
358 0 : if (type == CaptureDeviceType::Application) {
359 0 : AppDeviceInfoImpl * pAppDeviceInfoImpl = new AppDeviceInfoImpl(id);
360 0 : if (!pAppDeviceInfoImpl || pAppDeviceInfoImpl->Init()) {
361 0 : delete pAppDeviceInfoImpl;
362 0 : pAppDeviceInfoImpl = NULL;
363 : }
364 0 : return pAppDeviceInfoImpl;
365 0 : } else if (type == CaptureDeviceType::Screen) {
366 0 : ScreenDeviceInfoImpl * pScreenDeviceInfoImpl = new ScreenDeviceInfoImpl(id);
367 0 : if (!pScreenDeviceInfoImpl || pScreenDeviceInfoImpl->Init()) {
368 0 : delete pScreenDeviceInfoImpl;
369 0 : pScreenDeviceInfoImpl = NULL;
370 : }
371 0 : return pScreenDeviceInfoImpl;
372 0 : } else if (type == CaptureDeviceType::Window) {
373 0 : WindowDeviceInfoImpl * pWindowDeviceInfoImpl = new WindowDeviceInfoImpl(id);
374 0 : if (!pWindowDeviceInfoImpl || pWindowDeviceInfoImpl->Init()) {
375 0 : delete pWindowDeviceInfoImpl;
376 0 : pWindowDeviceInfoImpl = NULL;
377 : }
378 0 : return pWindowDeviceInfoImpl;
379 : }
380 0 : return NULL;
381 : }
382 :
383 0 : const char* DesktopCaptureImpl::CurrentDeviceName() const {
384 0 : return _deviceUniqueId.c_str();
385 : }
386 :
387 0 : int32_t DesktopCaptureImpl::Init(const char* uniqueId,
388 : const CaptureDeviceType type) {
389 0 : DesktopCaptureOptions options = DesktopCaptureOptions::CreateDefault();
390 : // Leave desktop effects enabled during WebRTC captures.
391 0 : options.set_disable_effects(false);
392 :
393 0 : if (type == CaptureDeviceType::Application) {
394 0 : std::unique_ptr<DesktopCapturer> pAppCapturer = DesktopCapturer::CreateAppCapturer(options);
395 0 : if (!pAppCapturer) {
396 0 : return -1;
397 : }
398 :
399 0 : DesktopCapturer::SourceId sourceId = atoi(uniqueId);
400 0 : pAppCapturer->SelectSource(sourceId);
401 :
402 0 : MouseCursorMonitor *pMouseCursorMonitor = MouseCursorMonitor::CreateForScreen(options, webrtc::kFullDesktopScreenId);
403 0 : desktop_capturer_cursor_composer_ = std::unique_ptr<DesktopAndCursorComposer>(new DesktopAndCursorComposer(pAppCapturer.release(), pMouseCursorMonitor));
404 0 : } else if (type == CaptureDeviceType::Screen) {
405 0 : std::unique_ptr<DesktopCapturer> pScreenCapturer = DesktopCapturer::CreateScreenCapturer(options);
406 0 : if (!pScreenCapturer.get()) {
407 0 : return -1;
408 : }
409 :
410 0 : DesktopCapturer::SourceId sourceId = atoi(uniqueId);
411 0 : pScreenCapturer->SelectSource(sourceId);
412 :
413 : // Upstream removed the ShapeObserver
414 : //pScreenCapturer->SetMouseShapeObserver(this);
415 :
416 0 : MouseCursorMonitor *pMouseCursorMonitor = MouseCursorMonitor::CreateForScreen(options, sourceId);
417 0 : desktop_capturer_cursor_composer_ = std::unique_ptr<DesktopAndCursorComposer>(new DesktopAndCursorComposer(pScreenCapturer.release(), pMouseCursorMonitor));
418 0 : } else if (type == CaptureDeviceType::Window) {
419 0 : std::unique_ptr<DesktopCapturer> pWindowCapturer = DesktopCapturer::CreateWindowCapturer(options);
420 0 : if (!pWindowCapturer.get()) {
421 0 : return -1;
422 : }
423 :
424 0 : DesktopCapturer::SourceId sourceId = atoi(uniqueId);
425 0 : pWindowCapturer->SelectSource(sourceId);
426 :
427 0 : MouseCursorMonitor *pMouseCursorMonitor = MouseCursorMonitor::CreateForWindow(webrtc::DesktopCaptureOptions::CreateDefault(), sourceId);
428 0 : desktop_capturer_cursor_composer_ = std::unique_ptr<DesktopAndCursorComposer>(new DesktopAndCursorComposer(pWindowCapturer.release(), pMouseCursorMonitor));
429 : }
430 0 : _deviceUniqueId = uniqueId;
431 :
432 0 : return 0;
433 : }
434 :
435 0 : DesktopCaptureImpl::DesktopCaptureImpl(const int32_t id)
436 : : _id(id),
437 : _deviceUniqueId(""),
438 0 : _apiCs(*CriticalSectionWrapper::CreateCriticalSection()),
439 : _requestedCapability(),
440 0 : _callBackCs(*CriticalSectionWrapper::CreateCriticalSection()),
441 : _dataCallBack(NULL),
442 : _rotateFrame(kVideoRotation_0),
443 0 : last_capture_time_(rtc::TimeNanos()/rtc::kNumNanosecsPerMillisec),
444 : // XXX Note that this won't capture drift!
445 0 : delta_ntp_internal_ms_(Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() -
446 0 : last_capture_time_),
447 : time_event_(EventWrapper::Create()),
448 : mRefCount(0),
449 : #if defined(_WIN32)
450 : capturer_thread_(new rtc::PlatformUIThread(Run, this, "ScreenCaptureThread")),
451 : #else
452 0 : capturer_thread_(new rtc::PlatformThread(Run, this, "ScreenCaptureThread")),
453 : #endif
454 0 : started_(false) {
455 : //-> TODO @@NG why is this crashing (seen on Linux)
456 : //-> capturer_thread_->SetPriority(rtc::kHighPriority);
457 0 : _requestedCapability.width = kDefaultWidth;
458 0 : _requestedCapability.height = kDefaultHeight;
459 0 : _requestedCapability.maxFPS = 30;
460 0 : _requestedCapability.rawType = kVideoI420;
461 0 : _requestedCapability.codecType = kVideoCodecUnknown;
462 0 : memset(_incomingFrameTimesNanos, 0, sizeof(_incomingFrameTimesNanos));
463 0 : }
464 :
465 0 : DesktopCaptureImpl::~DesktopCaptureImpl() {
466 0 : time_event_->Set();
467 0 : capturer_thread_->Stop();
468 :
469 0 : DeRegisterCaptureDataCallback();
470 0 : delete &_callBackCs;
471 0 : delete &_apiCs;
472 0 : }
473 :
474 0 : void DesktopCaptureImpl::RegisterCaptureDataCallback(rtc::VideoSinkInterface<VideoFrame> *dataCallback)
475 : {
476 0 : CriticalSectionScoped cs(&_apiCs);
477 0 : CriticalSectionScoped cs2(&_callBackCs);
478 0 : _dataCallBack = dataCallback;
479 0 : }
480 :
481 0 : void DesktopCaptureImpl::DeRegisterCaptureDataCallback()
482 : {
483 0 : CriticalSectionScoped cs(&_apiCs);
484 0 : CriticalSectionScoped cs2(&_callBackCs);
485 0 : _dataCallBack = nullptr;
486 0 : }
487 :
488 0 : int32_t DesktopCaptureImpl::DeliverCapturedFrame(webrtc::VideoFrame& captureFrame,
489 : int64_t capture_time) {
490 0 : UpdateFrameCount(); // frame count used for local frame rate callback.
491 :
492 : // Set the capture time
493 0 : if (capture_time != 0) {
494 0 : captureFrame.set_render_time_ms(capture_time - delta_ntp_internal_ms_);
495 : } else {
496 0 : captureFrame.set_render_time_ms(rtc::TimeNanos()/rtc::kNumNanosecsPerMillisec);
497 : }
498 :
499 0 : if (captureFrame.render_time_ms() == last_capture_time_) {
500 : // We don't allow the same capture time for two frames, drop this one.
501 0 : return -1;
502 : }
503 0 : last_capture_time_ = captureFrame.render_time_ms();
504 :
505 0 : if (_dataCallBack) {
506 0 : _dataCallBack->OnFrame(captureFrame);
507 : }
508 :
509 0 : return 0;
510 : }
511 :
512 : // Copied from VideoCaptureImpl::IncomingFrame. See Bug 1038324
513 0 : int32_t DesktopCaptureImpl::IncomingFrame(uint8_t* videoFrame,
514 : size_t videoFrameLength,
515 : const VideoCaptureCapability& frameInfo,
516 : int64_t captureTime/*=0*/)
517 : {
518 : WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceVideoCapture, _id,
519 : "IncomingFrame width %d, height %d", (int) frameInfo.width,
520 : (int) frameInfo.height);
521 :
522 0 : int64_t startProcessTime = rtc::TimeNanos();
523 :
524 0 : CriticalSectionScoped cs(&_callBackCs);
525 :
526 0 : const int32_t width = frameInfo.width;
527 0 : const int32_t height = frameInfo.height;
528 :
529 0 : TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime);
530 :
531 0 : if (frameInfo.codecType == kVideoCodecUnknown) {
532 : // Not encoded, convert to I420.
533 : const VideoType commonVideoType =
534 0 : RawVideoTypeToCommonVideoVideoType(frameInfo.rawType);
535 :
536 0 : if (frameInfo.rawType != kVideoMJPEG &&
537 0 : CalcBufferSize(commonVideoType, width,
538 : abs(height)) != videoFrameLength) {
539 : WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
540 : "Wrong incoming frame length.");
541 0 : return -1;
542 : }
543 :
544 0 : int stride_y = width;
545 0 : int stride_uv = (width + 1) / 2;
546 0 : int target_width = width;
547 0 : int target_height = abs(height);
548 : // Rotating resolution when for 90/270 degree rotations.
549 0 : if (_rotateFrame == kVideoRotation_90 || _rotateFrame == kVideoRotation_270) {
550 0 : target_height = width;
551 0 : target_width = abs(height);
552 : }
553 :
554 : // Setting absolute height (in case it was negative).
555 : // In Windows, the image starts bottom left, instead of top left.
556 : // Setting a negative source height, inverts the image (within LibYuv).
557 0 : rtc::scoped_refptr<webrtc::I420Buffer> buffer;
558 0 : buffer = I420Buffer::Create(target_width, target_height, stride_y,
559 0 : stride_uv, stride_uv);
560 0 : const int conversionResult = ConvertToI420(commonVideoType,
561 : videoFrame,
562 : 0, 0, // No cropping
563 : width, height,
564 : videoFrameLength,
565 : _rotateFrame,
566 0 : buffer.get());
567 0 : webrtc::VideoFrame captureFrame(buffer, 0, 0, kVideoRotation_0);
568 0 : if (conversionResult < 0) {
569 : WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
570 : "Failed to convert capture frame from type %d to I420",
571 : frameInfo.rawType);
572 0 : return -1;
573 : }
574 :
575 0 : int32_t req_max_width = _requestedCapability.width & 0xffff;
576 0 : int32_t req_max_height = _requestedCapability.height & 0xffff;
577 0 : int32_t req_ideal_width = (_requestedCapability.width >> 16) & 0xffff;
578 0 : int32_t req_ideal_height = (_requestedCapability.height >> 16) & 0xffff;
579 :
580 0 : int32_t dest_max_width = std::min(req_max_width, target_width);
581 0 : int32_t dest_max_height = std::min(req_max_height, target_height);
582 0 : int32_t dst_width = std::min(req_ideal_width > 0 ? req_ideal_width : target_width, dest_max_width);
583 0 : int32_t dst_height = std::min(req_ideal_height > 0 ? req_ideal_height : target_height, dest_max_height);
584 :
585 : // scale to average of portrait and landscape
586 0 : float scale_width = (float)dst_width / (float)target_width;
587 0 : float scale_height = (float)dst_height / (float)target_height;
588 0 : float scale = (scale_width + scale_height) / 2;
589 0 : dst_width = (int)(scale * target_width);
590 0 : dst_height = (int)(scale * target_height);
591 :
592 : // if scaled rectangle exceeds max rectangle, scale to minimum of portrait and landscape
593 0 : if (dst_width > dest_max_width || dst_height > dest_max_height) {
594 0 : scale_width = (float)dest_max_width / (float)dst_width;
595 0 : scale_height = (float)dest_max_height / (float)dst_height;
596 0 : scale = std::min(scale_width, scale_height);
597 0 : dst_width = (int)(scale * dst_width);
598 0 : dst_height = (int)(scale * dst_height);
599 : }
600 :
601 0 : if (dst_width == target_width && dst_height == target_height) {
602 0 : DeliverCapturedFrame(captureFrame, captureTime);
603 : } else {
604 0 : rtc::scoped_refptr<webrtc::I420Buffer> buffer;
605 0 : buffer = I420Buffer::Create(dst_width, dst_height, stride_y,
606 0 : stride_uv, stride_uv);
607 :
608 0 : buffer->ScaleFrom(*captureFrame.video_frame_buffer().get());
609 0 : webrtc::VideoFrame scaledFrame(buffer, 0, 0, kVideoRotation_0);
610 0 : DeliverCapturedFrame(scaledFrame, captureTime);
611 : }
612 : } else {
613 0 : assert(false);
614 : return -1;
615 : }
616 :
617 : const int64_t processTime =
618 0 : (rtc::TimeNanos() - startProcessTime)/rtc::kNumNanosecsPerMillisec;
619 :
620 : if (processTime > 10) {
621 : WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id,
622 : "Too long processing time of Incoming frame: %ums",
623 : (unsigned int) processTime);
624 : }
625 :
626 0 : return 0;
627 : }
628 :
629 0 : int32_t DesktopCaptureImpl::SetCaptureRotation(VideoRotation rotation) {
630 0 : CriticalSectionScoped cs(&_apiCs);
631 0 : CriticalSectionScoped cs2(&_callBackCs);
632 0 : _rotateFrame = rotation;
633 0 : return 0;
634 : }
635 :
636 0 : bool DesktopCaptureImpl::SetApplyRotation(bool enable) {
637 0 : return true;
638 : }
639 :
640 0 : void DesktopCaptureImpl::UpdateFrameCount() {
641 0 : if (_incomingFrameTimesNanos[0] == 0) {
642 : // first no shift
643 : } else {
644 : // shift
645 0 : for (int i = (kFrameRateCountHistorySize - 2); i >= 0; i--) {
646 0 : _incomingFrameTimesNanos[i + 1] = _incomingFrameTimesNanos[i];
647 : }
648 : }
649 0 : _incomingFrameTimesNanos[0] = rtc::TimeNanos();
650 0 : }
651 :
652 0 : uint32_t DesktopCaptureImpl::CalculateFrameRate(int64_t now_ns)
653 : {
654 0 : int32_t num = 0;
655 0 : int32_t nrOfFrames = 0;
656 0 : for (num = 1; num < (kFrameRateCountHistorySize - 1); num++)
657 : {
658 0 : if (_incomingFrameTimesNanos[num] <= 0 ||
659 0 : (now_ns - _incomingFrameTimesNanos[num]) /
660 : rtc::kNumNanosecsPerMillisec >
661 : kFrameRateHistoryWindowMs) // don't use data older than 2sec
662 : {
663 : break;
664 : }
665 : else
666 : {
667 0 : nrOfFrames++;
668 : }
669 : }
670 0 : if (num > 1)
671 : {
672 0 : int64_t diff = (now_ns - _incomingFrameTimesNanos[num - 1]) /
673 0 : rtc::kNumNanosecsPerMillisec;
674 0 : if (diff > 0)
675 : {
676 0 : return uint32_t((nrOfFrames * 1000.0f / diff) + 0.5f);
677 : }
678 : }
679 :
680 0 : return nrOfFrames;
681 : }
682 :
683 0 : int32_t DesktopCaptureImpl::StartCapture(const VideoCaptureCapability& capability) {
684 0 : _requestedCapability = capability;
685 : #if defined(_WIN32)
686 : uint32_t maxFPSNeeded = 1000/_requestedCapability.maxFPS;
687 : capturer_thread_->RequestCallbackTimer(maxFPSNeeded);
688 : #endif
689 :
690 0 : desktop_capturer_cursor_composer_->Start(this);
691 0 : capturer_thread_->Start();
692 0 : started_ = true;
693 :
694 0 : return 0;
695 : }
696 :
697 0 : int32_t DesktopCaptureImpl::StopCapture() {
698 0 : if (started_) {
699 0 : capturer_thread_->Stop(); // thread is guaranteed stopped before this returns
700 0 : desktop_capturer_cursor_composer_->Stop();
701 0 : started_ = false;
702 0 : return 0;
703 : }
704 0 : return -1;
705 : }
706 :
707 0 : bool DesktopCaptureImpl::CaptureStarted() {
708 0 : return started_;
709 : }
710 :
711 0 : int32_t DesktopCaptureImpl::CaptureSettings(VideoCaptureCapability& settings) {
712 0 : return -1;
713 : }
714 :
715 0 : void DesktopCaptureImpl::OnCaptureResult(DesktopCapturer::Result result,
716 : std::unique_ptr<DesktopFrame> frame) {
717 0 : if (frame.get() == nullptr) return;
718 0 : uint8_t * videoFrame = frame->data();
719 0 : VideoCaptureCapability frameInfo;
720 0 : frameInfo.width = frame->size().width();
721 0 : frameInfo.height = frame->size().height();
722 0 : frameInfo.rawType = kVideoARGB;
723 :
724 : // combine cursor in frame
725 : // Latest WebRTC already support it by DesktopFrameWithCursor/DesktopAndCursorComposer.
726 :
727 0 : size_t videoFrameLength = frameInfo.width * frameInfo.height * DesktopFrame::kBytesPerPixel;
728 0 : IncomingFrame(videoFrame, videoFrameLength, frameInfo);
729 : }
730 :
731 0 : void DesktopCaptureImpl::process() {
732 0 : DesktopRect desktop_rect;
733 0 : DesktopRegion desktop_region;
734 :
735 : #if !defined(_WIN32)
736 0 : int64_t startProcessTime = rtc::TimeNanos();
737 : #endif
738 :
739 0 : desktop_capturer_cursor_composer_->CaptureFrame();
740 :
741 : #if !defined(_WIN32)
742 : const uint32_t processTime =
743 0 : ((uint32_t)(rtc::TimeNanos() - startProcessTime))/rtc::kNumNanosecsPerMillisec;
744 : // Use at most x% CPU or limit framerate
745 0 : const uint32_t maxFPSNeeded = 1000/_requestedCapability.maxFPS;
746 0 : const float sleepTimeFactor = (100.0f / kMaxDesktopCaptureCpuUsage) - 1.0f;
747 0 : const uint32_t sleepTime = sleepTimeFactor * processTime;
748 0 : time_event_->Wait(std::max<uint32_t>(maxFPSNeeded, sleepTime));
749 : #endif
750 0 : }
751 :
752 : } // namespace webrtc
|