diff --git a/webrtc/modules/desktop_capture/win/d3d_device.cc b/webrtc/modules/desktop_capture/win/d3d_device.cc index 0884314a7c..f1d3c57242 100644 --- a/webrtc/modules/desktop_capture/win/d3d_device.cc +++ b/webrtc/modules/desktop_capture/win/d3d_device.cc @@ -69,6 +69,7 @@ std::vector D3dDevice::EnumDevices() { _com_error error = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast(factory.GetAddressOf())); if (error.Error() != S_OK || !factory) { + LOG(LS_WARNING) << "Cannot create IDXGIFactory1."; return std::vector(); } @@ -78,17 +79,15 @@ std::vector D3dDevice::EnumDevices() { error = factory->EnumAdapters(i, adapter.GetAddressOf()); if (error.Error() == S_OK) { D3dDevice device; - if (!device.Initialize(adapter)) { - return std::vector(); + if (device.Initialize(adapter)) { + result.push_back(std::move(device)); } - result.push_back(std::move(device)); } else if (error.Error() == DXGI_ERROR_NOT_FOUND) { break; } else { LOG(LS_WARNING) << "IDXGIFactory1::EnumAdapters returns an unexpected " "error " << error.ErrorMessage() << " with code " << error.Error(); - return std::vector(); } } return result; diff --git a/webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.cc b/webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.cc index a73f9e39f7..0d76bd7c31 100644 --- a/webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.cc +++ b/webrtc/modules/desktop_capture/win/dxgi_adapter_duplicator.cc @@ -52,12 +52,19 @@ bool DxgiAdapterDuplicator::DoInitialize() { break; } + if (error.Error() == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) { + LOG(LS_WARNING) << "IDXGIAdapter::EnumOutputs returns " + "NOT_CURRENTLY_AVAILABLE. This may happen when " + "running in session 0."; + break; + } + if (error.Error() != S_OK || !output) { LOG(LS_WARNING) << "IDXGIAdapter::EnumOutputs returns an unexpected " "result " << error.ErrorMessage() << " with error code" << error.Error(); - return false; + continue; } DXGI_OUTPUT_DESC desc; @@ -70,12 +77,17 @@ bool DxgiAdapterDuplicator::DoInitialize() { LOG(LS_WARNING) << "Failed to convert IDXGIOutput to IDXGIOutput1, " "this usually means the system does not support " "DirectX 11"; - return false; + continue; } - duplicators_.emplace_back(device_, output1, desc); - if (!duplicators_.back().Initialize()) { - return false; + DxgiOutputDuplicator duplicator(device_, output1, desc); + if (!duplicator.Initialize()) { + LOG(LS_WARNING) << "Failed to initialize DxgiOutputDuplicator on " + "output " + << i; + continue; } + + duplicators_.push_back(std::move(duplicator)); desktop_rect_.UnionWith(duplicators_.back().desktop_rect()); } } else { @@ -83,7 +95,12 @@ bool DxgiAdapterDuplicator::DoInitialize() { << ", ignore."; } } - return true; + + if (duplicators_.empty()) { + LOG(LS_WARNING) << "Cannot initialize any DxgiOutputDuplicator instance."; + } + + return !duplicators_.empty(); } void DxgiAdapterDuplicator::Setup(Context* context) { diff --git a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc index a0bc95fff1..9ade05b3a3 100644 --- a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc +++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc @@ -25,6 +25,22 @@ namespace webrtc { +namespace { + +// TODO(zijiehe): This function should be public as +// static bool DxgiDuplicatorController::IsSessionUnsupported() +bool IsRunningInSession0() { + DWORD session_id = 0; + if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id)) { + LOG(LS_WARNING) << "Failed to retrieve current session Id, current binary " + "may not have required priviledge."; + return true; + } + return session_id == 0; +} + +} // namespace + // static rtc::scoped_refptr DxgiDuplicatorController::Instance() { @@ -58,12 +74,17 @@ bool DxgiDuplicatorController::IsSupported() { } bool DxgiDuplicatorController::RetrieveD3dInfo(D3dInfo* info) { - rtc::CritScope lock(&lock_); - if (!Initialize()) { - return false; + bool result = false; + { + rtc::CritScope lock(&lock_); + result = Initialize(); + *info = d3d_info_; } - *info = d3d_info_; - return true; + if (!result) { + LOG(LS_WARNING) << "Failed to initialize DXGI components, the D3dInfo " + "retrieved may not accurate or out of date."; + } + return result; } DxgiDuplicatorController::Result @@ -117,6 +138,12 @@ DxgiDuplicatorController::DoDuplicate(DxgiFrame* frame, int monitor_id) { } if (!Initialize()) { + if (succeeded_duplications_ == 0 && IsRunningInSession0()) { + LOG(LS_WARNING) << "Current binary is running in session 0. DXGI " + "components cannot be initialized."; + return Result::UNSUPPORTED_SESSION; + } + // Cannot initialize COM components now, display mode may be changing. return Result::INITIALIZATION_FAILED; } @@ -128,6 +155,7 @@ DxgiDuplicatorController::DoDuplicate(DxgiFrame* frame, int monitor_id) { frame->frame()->mutable_updated_region()->Clear(); if (DoDuplicateUnlocked(frame->context(), monitor_id, frame->frame())) { + succeeded_duplications_++; return Result::SUCCEEDED; } if (monitor_id >= ScreenCountUnlocked()) { @@ -180,15 +208,11 @@ bool DxgiDuplicatorController::DoInitialize() { std::vector devices = D3dDevice::EnumDevices(); if (devices.empty()) { + LOG(LS_WARNING) << "No D3dDevice found."; return false; } for (size_t i = 0; i < devices.size(); i++) { - duplicators_.emplace_back(devices[i]); - if (!duplicators_.back().Initialize()) { - return false; - } - D3D_FEATURE_LEVEL feature_level = devices[i].d3d_device()->GetFeatureLevel(); if (d3d_info_.max_feature_level == 0 || @@ -200,6 +224,20 @@ bool DxgiDuplicatorController::DoInitialize() { d3d_info_.min_feature_level = feature_level; } + DxgiAdapterDuplicator duplicator(devices[i]); + // There may be several video cards on the system, some of them may not + // support IDXGOutputDuplication. But they should not impact others from + // taking effect, so we should continually try other adapters. This usually + // happens when a non-official virtual adapter is installed on the system. + if (!duplicator.Initialize()) { + LOG(LS_WARNING) << "Failed to initialize DxgiAdapterDuplicator on " + "adapter " + << i; + continue; + } + RTC_DCHECK(!duplicator.desktop_rect().is_empty()); + duplicators_.push_back(std::move(duplicator)); + desktop_rect_.UnionWith(duplicators_.back().desktop_rect()); } TranslateRect(); @@ -212,7 +250,12 @@ bool DxgiDuplicatorController::DoInitialize() { } identity_++; - return true; + + if (duplicators_.empty()) { + LOG(LS_WARNING) << "Cannot initialize any DxgiAdapterDuplicator instance."; + } + + return !duplicators_.empty(); } void DxgiDuplicatorController::Deinitialize() { diff --git a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h index 308b2f3a74..a254b6d141 100644 --- a/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h +++ b/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h @@ -60,6 +60,7 @@ class DxgiDuplicatorController { enum class Result { SUCCEEDED, + UNSUPPORTED_SESSION, FRAME_PREPARE_FAILED, INITIALIZATION_FAILED, DUPLICATION_FAILED, @@ -74,7 +75,9 @@ class DxgiDuplicatorController { // Detects whether the system supports DXGI based capturer. bool IsSupported(); - // Returns a copy of D3dInfo composed by last Initialize() function call. + // Returns a copy of D3dInfo composed by last Initialize() function call. This + // function always copies the latest information into |info|. But once the + // function returns false, the information in |info| may not accurate. bool RetrieveD3dInfo(D3dInfo* info); // Captures current screen and writes into |frame|. @@ -211,6 +214,8 @@ class DxgiDuplicatorController { std::vector duplicators_; D3dInfo d3d_info_; ResolutionChangeDetector resolution_change_detector_; + // A number to indicate how many succeeded duplications have been performed. + uint32_t succeeded_duplications_ = 0; }; } // namespace webrtc diff --git a/webrtc/modules/desktop_capture/win/dxgi_frame.cc b/webrtc/modules/desktop_capture/win/dxgi_frame.cc index 6e33b64527..79a9016b0f 100644 --- a/webrtc/modules/desktop_capture/win/dxgi_frame.cc +++ b/webrtc/modules/desktop_capture/win/dxgi_frame.cc @@ -15,6 +15,7 @@ #include #include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" #include "webrtc/modules/desktop_capture/desktop_frame.h" #include "webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h" @@ -46,6 +47,7 @@ bool DxgiFrame::Prepare(DesktopSize size, DesktopCapturer::SourceId source_id) { frame.reset(new BasicDesktopFrame(size)); } if (!frame) { + LOG(LS_WARNING) << "DxgiFrame cannot create a new DesktopFrame."; return false; } // DirectX capturer won't paint each pixel in the frame due to its one diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.cc b/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.cc index 331379b8a5..f865a1e6e0 100644 --- a/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.cc +++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.cc @@ -74,6 +74,12 @@ void ScreenCapturerWinDirectx::CaptureFrame() { using DuplicateResult = DxgiDuplicatorController::Result; switch (result) { + case DuplicateResult::UNSUPPORTED_SESSION: { + LOG(LS_ERROR) << "Current binary is running on a session not supported " + "by DirectX screen capturer."; + callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr); + break; + } case DuplicateResult::FRAME_PREPARE_FAILED: { LOG(LS_ERROR) << "Failed to allocate a new DesktopFrame."; // This usually means we do not have enough memory or SharedMemoryFactory