Use WindowFinder in WindowCapturer to detect IsOccluded()
In this change,
bool DesktopCapturer::IsOccluded(const DesktopVector& pos);
is added to DesktopCapturer interface. This function returns true if the |pos|
is hidden by other elements on the display.
The function expects to return false for ScreenCapturer implementations:
everything is visible on the screen.
In WindowCapturer implementations, WindowFinder is expected to be used to help
detect the WindowId under |pos|. If the window_id_ equals to the window id
returned by WindowFinder, this function returns false.
To ensure the correct coordinate is used, a comment is also added to
WindowFinder::GetWindowUnderPoint() function. Considering it's used only in
desktop_capture module, using system coordinate is simpler.
Bug: webrtc:7950
Change-Id: I8ac4fbd5f4a612388f1593907805cfb2c359f70f
Reviewed-on: https://chromium-review.googlesource.com/636784
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Commit-Queue: Zijie He <zijiehe@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#19590}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 12827113a1c1467065b124886dd658e6274a5ba5
diff --git a/modules/desktop_capture/desktop_capture_options.h b/modules/desktop_capture/desktop_capture_options.h
index e10cab7..8956275 100644
--- a/modules/desktop_capture/desktop_capture_options.h
+++ b/modules/desktop_capture/desktop_capture_options.h
@@ -49,14 +49,22 @@
#endif
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+ // TODO(zijiehe): Remove both DesktopConfigurationMonitor and
+ // FullScreenChromeWindowDetector out of DesktopCaptureOptions. It's not
+ // reasonable for external consumers to set these two parameters.
DesktopConfigurationMonitor* configuration_monitor() const {
return configuration_monitor_;
}
+ // If nullptr is set, ScreenCapturer won't work and WindowCapturer may return
+ // inaccurate result from IsOccluded() function.
void set_configuration_monitor(
rtc::scoped_refptr<DesktopConfigurationMonitor> m) {
configuration_monitor_ = m;
}
+ // TODO(zijiehe): Instead of FullScreenChromeWindowDetector, provide a
+ // FullScreenWindowDetector for external consumers to detect the target
+ // fullscreen window.
FullScreenChromeWindowDetector* full_screen_chrome_window_detector() const {
return full_screen_window_detector_;
}
@@ -83,8 +91,6 @@
// Flag that should be set if the consumer uses updated_region() and the
// capturer should try to provide correct updated_region() for the frames it
// generates (e.g. by comparing each frame with the previous one).
- // TODO(zijiehe): WindowCapturer ignores this opinion until we merge
- // ScreenCapturer and WindowCapturer interfaces.
bool detect_updated_region() const { return detect_updated_region_; }
void set_detect_updated_region(bool detect_updated_region) {
detect_updated_region_ = detect_updated_region;
diff --git a/modules/desktop_capture/desktop_capturer.cc b/modules/desktop_capture/desktop_capturer.cc
index e655474..67d3520 100644
--- a/modules/desktop_capture/desktop_capturer.cc
+++ b/modules/desktop_capture/desktop_capturer.cc
@@ -34,6 +34,10 @@
return false;
}
+bool DesktopCapturer::IsOccluded(const DesktopVector& pos) {
+ return false;
+}
+
// static
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateWindowCapturer(
const DesktopCaptureOptions& options) {
diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h
index 5af69b8..4f44ce1 100644
--- a/modules/desktop_capture/desktop_capturer.h
+++ b/modules/desktop_capture/desktop_capturer.h
@@ -119,6 +119,13 @@
// implementation does not support this functionality.
virtual bool FocusOnSelectedSource();
+ // Returns true if the |pos| on the selected source is covered by other
+ // elements on the display, and is not visible to the users.
+ // |pos| is in full desktop coordinates, i.e. the top-left monitor always
+ // starts from (0, 0).
+ // The return value if |pos| is out of the scope of the source is undefined.
+ virtual bool IsOccluded(const DesktopVector& pos);
+
// Creates a DesktopCapturer instance which targets to capture windows.
static std::unique_ptr<DesktopCapturer> CreateWindowCapturer(
const DesktopCaptureOptions& options);
diff --git a/modules/desktop_capture/mac/window_list_utils.h b/modules/desktop_capture/mac/window_list_utils.h
index a3cd507..7147e89 100644
--- a/modules/desktop_capture/mac/window_list_utils.h
+++ b/modules/desktop_capture/mac/window_list_utils.h
@@ -51,7 +51,9 @@
WindowId GetWindowId(CFDictionaryRef window);
// Returns the bounds of |window|. If |window| is not a window or the bounds
-// cannot be retrieved, this function returns an empty DesktopRect.
+// cannot be retrieved, this function returns an empty DesktopRect. The returned
+// DesktopRect is in system coordinate, i.e. the primary monitor always starts
+// from (0, 0).
DesktopRect GetWindowBounds(CFDictionaryRef window);
} // namespace webrtc
diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm
index c3a6d00..4f1c191 100644
--- a/modules/desktop_capture/window_capturer_mac.mm
+++ b/modules/desktop_capture/window_capturer_mac.mm
@@ -13,10 +13,14 @@
#include <Cocoa/Cocoa.h>
#include <CoreFoundation/CoreFoundation.h>
+#include <utility>
+
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_capturer.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/window_finder_mac.h"
#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
+#include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h"
#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
#include "webrtc/modules/desktop_capture/mac/window_list_utils.h"
#include "webrtc/rtc_base/constructormagic.h"
@@ -44,7 +48,9 @@
class WindowCapturerMac : public DesktopCapturer {
public:
explicit WindowCapturerMac(rtc::scoped_refptr<FullScreenChromeWindowDetector>
- full_screen_chrome_window_detector);
+ full_screen_chrome_window_detector,
+ rtc::scoped_refptr<DesktopConfigurationMonitor>
+ configuration_monitor);
~WindowCapturerMac() override;
// DesktopCapturer interface.
@@ -53,6 +59,7 @@
bool GetSourceList(SourceList* sources) override;
bool SelectSource(SourceId id) override;
bool FocusOnSelectedSource() override;
+ bool IsOccluded(const DesktopVector& pos) override;
private:
Callback* callback_ = nullptr;
@@ -60,16 +67,23 @@
// The window being captured.
CGWindowID window_id_ = 0;
- rtc::scoped_refptr<FullScreenChromeWindowDetector>
+ const rtc::scoped_refptr<FullScreenChromeWindowDetector>
full_screen_chrome_window_detector_;
+ const rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
+
+ WindowFinderMac window_finder_;
+
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac);
};
WindowCapturerMac::WindowCapturerMac(
rtc::scoped_refptr<FullScreenChromeWindowDetector>
- full_screen_chrome_window_detector)
- : full_screen_chrome_window_detector_(full_screen_chrome_window_detector) {}
+ full_screen_chrome_window_detector,
+ rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor)
+ : full_screen_chrome_window_detector_(
+ std::move(full_screen_chrome_window_detector)),
+ configuration_monitor_(std::move(configuration_monitor)) {}
WindowCapturerMac::~WindowCapturerMac() {}
@@ -121,6 +135,17 @@
return result;
}
+bool WindowCapturerMac::IsOccluded(const DesktopVector& pos) {
+ DesktopVector sys_pos = pos;
+ if (configuration_monitor_) {
+ configuration_monitor_->Lock();
+ auto configuration = configuration_monitor_->desktop_configuration();
+ configuration_monitor_->Unlock();
+ sys_pos = pos.add(configuration.bounds.top_left());
+ }
+ return window_finder_.GetWindowUnderPoint(sys_pos) != window_id_;
+}
+
void WindowCapturerMac::Start(Callback* callback) {
assert(!callback_);
assert(callback);
@@ -192,7 +217,8 @@
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
const DesktopCaptureOptions& options) {
return std::unique_ptr<DesktopCapturer>(
- new WindowCapturerMac(options.full_screen_chrome_window_detector()));
+ new WindowCapturerMac(options.full_screen_chrome_window_detector(),
+ options.configuration_monitor()));
}
} // namespace webrtc
diff --git a/modules/desktop_capture/window_capturer_win.cc b/modules/desktop_capture/window_capturer_win.cc
index dde91aa..880a719 100644
--- a/modules/desktop_capture/window_capturer_win.cc
+++ b/modules/desktop_capture/window_capturer_win.cc
@@ -14,6 +14,8 @@
#include "webrtc/modules/desktop_capture/desktop_capturer.h"
#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
+#include "webrtc/modules/desktop_capture/window_finder_win.h"
+#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
#include "webrtc/modules/desktop_capture/win/window_capture_utils.h"
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/constructormagic.h"
@@ -90,6 +92,7 @@
bool GetSourceList(SourceList* sources) override;
bool SelectSource(SourceId id) override;
bool FocusOnSelectedSource() override;
+ bool IsOccluded(const DesktopVector& pos) override;
private:
Callback* callback_ = nullptr;
@@ -106,6 +109,8 @@
// are interleaved with Capture() calls.
std::map<HWND, DesktopSize> window_size_map_;
+ WindowFinderWin window_finder_;
+
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerWin);
};
@@ -152,6 +157,12 @@
SetForegroundWindow(window_) != FALSE;
}
+bool WindowCapturerWin::IsOccluded(const DesktopVector& pos) {
+ DesktopVector sys_pos = pos.add(GetFullscreenRect().top_left());
+ return reinterpret_cast<HWND>(window_finder_.GetWindowUnderPoint(sys_pos))
+ != window_;
+}
+
void WindowCapturerWin::Start(Callback* callback) {
assert(!callback_);
assert(callback);
diff --git a/modules/desktop_capture/window_capturer_x11.cc b/modules/desktop_capture/window_capturer_x11.cc
index 3ea69a1..5d01a15 100644
--- a/modules/desktop_capture/window_capturer_x11.cc
+++ b/modules/desktop_capture/window_capturer_x11.cc
@@ -17,6 +17,7 @@
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_capturer.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/window_finder_x11.h"
#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
#include "webrtc/modules/desktop_capture/x11/window_list_utils.h"
#include "webrtc/modules/desktop_capture/x11/x_atom_cache.h"
@@ -42,6 +43,7 @@
bool GetSourceList(SourceList* sources) override;
bool SelectSource(SourceId id) override;
bool FocusOnSelectedSource() override;
+ bool IsOccluded(const DesktopVector& pos) override;
// SharedXDisplay::XEventHandler interface.
bool HandleXEvent(const XEvent& event) override;
@@ -61,13 +63,15 @@
::Window selected_window_ = 0;
XServerPixelBuffer x_server_pixel_buffer_;
XAtomCache atom_cache_;
+ WindowFinderX11 window_finder_;
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux);
};
WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options)
: x_display_(options.x_display()),
- atom_cache_(display()) {
+ atom_cache_(display()),
+ window_finder_(&atom_cache_) {
int event_base, error_base, major_version, minor_version;
if (XCompositeQueryExtension(display(), &event_base, &error_base) &&
XCompositeQueryVersion(display(), &major_version, &minor_version) &&
@@ -216,6 +220,11 @@
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
}
+bool WindowCapturerLinux::IsOccluded(const DesktopVector& pos) {
+ return window_finder_.GetWindowUnderPoint(pos) !=
+ static_cast<WindowId>(selected_window_);
+}
+
bool WindowCapturerLinux::HandleXEvent(const XEvent& event) {
if (event.type == ConfigureNotify) {
XConfigureEvent xce = event.xconfigure;
diff --git a/modules/desktop_capture/window_finder.h b/modules/desktop_capture/window_finder.h
index 4c46c48..90f3513 100644
--- a/modules/desktop_capture/window_finder.h
+++ b/modules/desktop_capture/window_finder.h
@@ -25,6 +25,8 @@
// Returns the id of the visible window under |point|. This function returns
// kNullWindowId if no window is under |point| and the platform does not have
// "root window" concept, i.e. the visible area under |point| is the desktop.
+ // |point| is always in system coordinate, i.e. the primary monitor always
+ // starts from (0, 0).
virtual WindowId GetWindowUnderPoint(DesktopVector point) = 0;
};
diff --git a/modules/desktop_capture/window_finder_mac.h b/modules/desktop_capture/window_finder_mac.h
index 4b01600..9f872ea 100644
--- a/modules/desktop_capture/window_finder_mac.h
+++ b/modules/desktop_capture/window_finder_mac.h
@@ -15,7 +15,7 @@
namespace webrtc {
-// The implementation of WindowFinder for Windows.
+// The implementation of WindowFinder for Mac OSX.
class WindowFinderMac final : public WindowFinder {
public:
WindowFinderMac();
diff --git a/modules/desktop_capture/window_finder_x11.h b/modules/desktop_capture/window_finder_x11.h
index 9a4e020..6dec89b 100644
--- a/modules/desktop_capture/window_finder_x11.h
+++ b/modules/desktop_capture/window_finder_x11.h
@@ -17,7 +17,7 @@
class XAtomCache;
-// The implementation of WindowFinder for Windows.
+// The implementation of WindowFinder for X11.
class WindowFinderX11 final : public WindowFinder {
public:
explicit WindowFinderX11(XAtomCache* cache);