From d1208c26b1cdb536fdec942207033711101d5d26 Mon Sep 17 00:00:00 2001 From: Gary Kacmarcik Date: Fri, 14 Dec 2018 11:37:13 -0800 Subject: [PATCH] Desktop capturer: Add OnDisplayChanged callback This adds support for a new DesktopCapturer::Callback method OnDisplayChanged that is sent at the start of a desktop capture session and whenever the display geometry changes. This cl adds the basic structure to call this api at the start of the capture session. Currently Windows only. A follow-up cl will add support to call this whenever the display geometry changes. Bug: webrtc:10122, chromium:915411 Change-Id: Ie7283be5992454180daab1a60f58a3b2efdfed56 Reviewed-on: https://webrtc-review.googlesource.com/c/114020 Commit-Queue: Gary Kacmarcik Reviewed-by: Brave Yao Cr-Commit-Position: refs/heads/master@{#26053} --- ...blank_detector_desktop_capturer_wrapper.cc | 6 +++ .../blank_detector_desktop_capturer_wrapper.h | 1 + .../cropping_window_capturer.cc | 5 +++ .../cropping_window_capturer.h | 1 + modules/desktop_capture/desktop_capturer.h | 22 +++++++++- .../desktop_capturer_differ_wrapper.cc | 6 +++ .../desktop_capturer_differ_wrapper.h | 1 + .../fallback_desktop_capturer_wrapper.cc | 6 +++ .../fallback_desktop_capturer_wrapper.h | 1 + .../win/screen_capture_utils.cc | 43 +++++++++++++++++++ .../win/screen_capture_utils.h | 4 ++ .../win/screen_capturer_win_directx.cc | 5 +++ .../win/screen_capturer_win_gdi.cc | 7 ++- 13 files changed, 105 insertions(+), 3 deletions(-) diff --git a/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.cc b/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.cc index 061aab07a8..4518778d4e 100644 --- a/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.cc +++ b/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.cc @@ -91,6 +91,12 @@ void BlankDetectorDesktopCapturerWrapper::OnCaptureResult( std::unique_ptr()); } +void BlankDetectorDesktopCapturerWrapper::OnDisplayChanged( + std::unique_ptr displays) { + RTC_DCHECK(callback_); + callback_->OnDisplayChanged(std::move(displays)); +} + bool BlankDetectorDesktopCapturerWrapper::IsBlankFrame( const DesktopFrame& frame) const { // We will check 7489 pixels for a frame with 1024 x 768 resolution. diff --git a/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.h b/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.h index 6ec6b1a82f..d435022b74 100644 --- a/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.h +++ b/modules/desktop_capture/blank_detector_desktop_capturer_wrapper.h @@ -51,6 +51,7 @@ class BlankDetectorDesktopCapturerWrapper final // DesktopCapturer::Callback interface. void OnCaptureResult(Result result, std::unique_ptr frame) override; + void OnDisplayChanged(std::unique_ptr displays) override; bool IsBlankFrame(const DesktopFrame& frame) const; diff --git a/modules/desktop_capture/cropping_window_capturer.cc b/modules/desktop_capture/cropping_window_capturer.cc index a03ae0c6d5..b536c35709 100644 --- a/modules/desktop_capture/cropping_window_capturer.cc +++ b/modules/desktop_capture/cropping_window_capturer.cc @@ -103,6 +103,11 @@ void CroppingWindowCapturer::OnCaptureResult( CreateCroppedDesktopFrame(std::move(screen_frame), window_rect)); } +void CroppingWindowCapturer::OnDisplayChanged( + std::unique_ptr displays) { + callback_->OnDisplayChanged(std::move(displays)); +} + bool CroppingWindowCapturer::IsOccluded(const DesktopVector& pos) { // Returns true if either capturer returns true. if (window_capturer_->IsOccluded(pos)) { diff --git a/modules/desktop_capture/cropping_window_capturer.h b/modules/desktop_capture/cropping_window_capturer.h index f9ad36cd4c..e3773db001 100644 --- a/modules/desktop_capture/cropping_window_capturer.h +++ b/modules/desktop_capture/cropping_window_capturer.h @@ -49,6 +49,7 @@ class RTC_EXPORT CroppingWindowCapturer : public DesktopCapturer, // intercept the capture result. void OnCaptureResult(DesktopCapturer::Result result, std::unique_ptr frame) override; + void OnDisplayChanged(std::unique_ptr displays) override; protected: explicit CroppingWindowCapturer(const DesktopCaptureOptions& options); diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h index f9dacc1f7a..bc6ee8bfae 100644 --- a/modules/desktop_capture/desktop_capturer.h +++ b/modules/desktop_capture/desktop_capturer.h @@ -47,6 +47,21 @@ class RTC_EXPORT DesktopCapturer { MAX_VALUE = ERROR_PERMANENT }; + typedef intptr_t SourceId; + + struct DesktopDisplay { + // The unique id to represent a Source of current DesktopCapturer. + SourceId id; + + int32_t x, y; + uint32_t width, height; + uint32_t dpi; // Number of pixels per logical inch. + uint32_t bpp; // Number of bits per pixel. + bool is_default; // True if this is the default display. + }; + + typedef std::vector DisplayList; + // Interface that must be implemented by the DesktopCapturer consumers. class Callback { public: @@ -55,12 +70,15 @@ class RTC_EXPORT DesktopCapturer { virtual void OnCaptureResult(Result result, std::unique_ptr frame) = 0; + // Called once at the start of a session and again anytime the monitor + // configuration is changed. + // TODO(garykac): Make pure virtual after Chromium is updated. + virtual void OnDisplayChanged(std::unique_ptr displays) {} + protected: virtual ~Callback() {} }; - typedef intptr_t SourceId; - static_assert(std::is_same::value, "SourceId should be a same type as ScreenId."); diff --git a/modules/desktop_capture/desktop_capturer_differ_wrapper.cc b/modules/desktop_capture/desktop_capturer_differ_wrapper.cc index 4759f9ab94..2d0217eab5 100644 --- a/modules/desktop_capture/desktop_capturer_differ_wrapper.cc +++ b/modules/desktop_capture/desktop_capturer_differ_wrapper.cc @@ -222,4 +222,10 @@ void DesktopCapturerDifferWrapper::OnCaptureResult( callback_->OnCaptureResult(result, std::move(frame)); } +void DesktopCapturerDifferWrapper::OnDisplayChanged( + std::unique_ptr displays) { + RTC_DCHECK(callback_); + callback_->OnDisplayChanged(std::move(displays)); +} + } // namespace webrtc diff --git a/modules/desktop_capture/desktop_capturer_differ_wrapper.h b/modules/desktop_capture/desktop_capturer_differ_wrapper.h index 1c5a621415..45d0ebb338 100644 --- a/modules/desktop_capture/desktop_capturer_differ_wrapper.h +++ b/modules/desktop_capture/desktop_capturer_differ_wrapper.h @@ -55,6 +55,7 @@ class DesktopCapturerDifferWrapper : public DesktopCapturer, // DesktopCapturer::Callback interface. void OnCaptureResult(Result result, std::unique_ptr frame) override; + void OnDisplayChanged(std::unique_ptr displays) override; const std::unique_ptr base_capturer_; DesktopCapturer::Callback* callback_; diff --git a/modules/desktop_capture/fallback_desktop_capturer_wrapper.cc b/modules/desktop_capture/fallback_desktop_capturer_wrapper.cc index 5f60f1e3ea..0dee0c0654 100644 --- a/modules/desktop_capture/fallback_desktop_capturer_wrapper.cc +++ b/modules/desktop_capture/fallback_desktop_capturer_wrapper.cc @@ -179,4 +179,10 @@ void FallbackDesktopCapturerWrapper::OnCaptureResult( secondary_capturer_->CaptureFrame(); } +void FallbackDesktopCapturerWrapper::OnDisplayChanged( + std::unique_ptr displays) { + RTC_DCHECK(callback_); + callback_->OnDisplayChanged(std::move(displays)); +} + } // namespace webrtc diff --git a/modules/desktop_capture/fallback_desktop_capturer_wrapper.h b/modules/desktop_capture/fallback_desktop_capturer_wrapper.h index 2855eae7ee..dc3817cc9a 100644 --- a/modules/desktop_capture/fallback_desktop_capturer_wrapper.h +++ b/modules/desktop_capture/fallback_desktop_capturer_wrapper.h @@ -51,6 +51,7 @@ class FallbackDesktopCapturerWrapper final : public DesktopCapturer, // DesktopCapturer::Callback interface. void OnCaptureResult(Result result, std::unique_ptr frame) override; + void OnDisplayChanged(std::unique_ptr displays) override; const std::unique_ptr main_capturer_; const std::unique_ptr secondary_capturer_; diff --git a/modules/desktop_capture/win/screen_capture_utils.cc b/modules/desktop_capture/win/screen_capture_utils.cc index e294497e55..99d30e9422 100644 --- a/modules/desktop_capture/win/screen_capture_utils.cc +++ b/modules/desktop_capture/win/screen_capture_utils.cc @@ -105,4 +105,47 @@ DesktopRect GetScreenRect(DesktopCapturer::SourceId screen, device_mode.dmPelsWidth, device_mode.dmPelsHeight); } +bool GetDisplayList(DesktopCapturer::DisplayList* displays) { + RTC_DCHECK_EQ(displays->size(), 0U); + + BOOL result = TRUE; + for (int device_index = 0;; ++device_index) { + DISPLAY_DEVICE device; + device.cb = sizeof(device); + result = EnumDisplayDevices(NULL, device_index, &device, 0); + + // |enum_result| is 0 if we have enumerated all devices. + if (!result) + break; + + // We only care about active displays. + if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE)) + continue; + + DesktopCapturer::DesktopDisplay display; + display.id = device_index; + + display.is_default = false; + if (device.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + display.is_default = true; + + // Get additional info about device. + DEVMODE devmode = {}; + devmode.dmSize = sizeof(devmode); + result = EnumDisplaySettingsEx(device.DeviceName, ENUM_CURRENT_SETTINGS, + &devmode, 0); + if (result) { + display.x = devmode.dmPosition.x; + display.y = devmode.dmPosition.y; + display.width = devmode.dmPelsWidth; + display.height = devmode.dmPelsHeight; + display.dpi = devmode.dmLogPixels; + display.bpp = devmode.dmBitsPerPel; + } + displays->push_back(display); + } + + return true; +} + } // namespace webrtc diff --git a/modules/desktop_capture/win/screen_capture_utils.h b/modules/desktop_capture/win/screen_capture_utils.h index f494dd2176..203cd43efc 100644 --- a/modules/desktop_capture/win/screen_capture_utils.h +++ b/modules/desktop_capture/win/screen_capture_utils.h @@ -42,6 +42,10 @@ DesktopRect GetFullscreenRect(); DesktopRect GetScreenRect(DesktopCapturer::SourceId screen, const std::wstring& device_key); +// Get the list of active displays, returning true if successful. +// The list of displays contains geometry information about each display. +bool GetDisplayList(DesktopCapturer::DisplayList* displays); + } // namespace webrtc #endif // MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURE_UTILS_H_ diff --git a/modules/desktop_capture/win/screen_capturer_win_directx.cc b/modules/desktop_capture/win/screen_capturer_win_directx.cc index f038c70cf5..79a09a2602 100644 --- a/modules/desktop_capture/win/screen_capturer_win_directx.cc +++ b/modules/desktop_capture/win/screen_capturer_win_directx.cc @@ -108,6 +108,11 @@ void ScreenCapturerWinDirectx::Start(Callback* callback) { RTC_DCHECK(callback); callback_ = callback; + + // Send initial desktop display summary. + auto displays = std::make_unique(); + if (GetDisplayList(displays.get())) + callback_->OnDisplayChanged(std::move(displays)); } void ScreenCapturerWinDirectx::SetSharedMemoryFactory( diff --git a/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/modules/desktop_capture/win/screen_capturer_win_gdi.cc index 03f8340bbc..9c8b2b9212 100644 --- a/modules/desktop_capture/win/screen_capturer_win_gdi.cc +++ b/modules/desktop_capture/win/screen_capturer_win_gdi.cc @@ -120,6 +120,11 @@ void ScreenCapturerWinGdi::Start(Callback* callback) { // under Windows 8 or higher. See crbug.com/124018. if (composition_func_) (*composition_func_)(DWM_EC_DISABLECOMPOSITION); + + // Send initial desktop display summary. + auto displays = std::make_unique(); + if (GetDisplayList(displays.get())) + callback_->OnDisplayChanged(std::move(displays)); } void ScreenCapturerWinGdi::PrepareCaptureResources() { @@ -220,7 +225,7 @@ bool ScreenCapturerWinGdi::CaptureImage() { RTC_LOG_GLE(LS_WARNING) << "BitBlt failed"; } - // Select back the previously selected object to that the device contect + // Select back the previously selected object so that the device context // could be destroyed independently of the bitmap if needed. SelectObject(memory_dc_, previous_object);