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 <garykac@chromium.org>
Reviewed-by: Brave Yao <braveyao@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26053}
This commit is contained in:
Gary Kacmarcik 2018-12-14 11:37:13 -08:00 committed by Commit Bot
parent 5a1de87e9a
commit d1208c26b1
13 changed files with 105 additions and 3 deletions

View File

@ -91,6 +91,12 @@ void BlankDetectorDesktopCapturerWrapper::OnCaptureResult(
std::unique_ptr<DesktopFrame>());
}
void BlankDetectorDesktopCapturerWrapper::OnDisplayChanged(
std::unique_ptr<DisplayList> 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.

View File

@ -51,6 +51,7 @@ class BlankDetectorDesktopCapturerWrapper final
// DesktopCapturer::Callback interface.
void OnCaptureResult(Result result,
std::unique_ptr<DesktopFrame> frame) override;
void OnDisplayChanged(std::unique_ptr<DisplayList> displays) override;
bool IsBlankFrame(const DesktopFrame& frame) const;

View File

@ -103,6 +103,11 @@ void CroppingWindowCapturer::OnCaptureResult(
CreateCroppedDesktopFrame(std::move(screen_frame), window_rect));
}
void CroppingWindowCapturer::OnDisplayChanged(
std::unique_ptr<DisplayList> displays) {
callback_->OnDisplayChanged(std::move(displays));
}
bool CroppingWindowCapturer::IsOccluded(const DesktopVector& pos) {
// Returns true if either capturer returns true.
if (window_capturer_->IsOccluded(pos)) {

View File

@ -49,6 +49,7 @@ class RTC_EXPORT CroppingWindowCapturer : public DesktopCapturer,
// intercept the capture result.
void OnCaptureResult(DesktopCapturer::Result result,
std::unique_ptr<DesktopFrame> frame) override;
void OnDisplayChanged(std::unique_ptr<DisplayList> displays) override;
protected:
explicit CroppingWindowCapturer(const DesktopCaptureOptions& options);

View File

@ -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<DesktopDisplay> 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<DesktopFrame> 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<DisplayList> displays) {}
protected:
virtual ~Callback() {}
};
typedef intptr_t SourceId;
static_assert(std::is_same<SourceId, ScreenId>::value,
"SourceId should be a same type as ScreenId.");

View File

@ -222,4 +222,10 @@ void DesktopCapturerDifferWrapper::OnCaptureResult(
callback_->OnCaptureResult(result, std::move(frame));
}
void DesktopCapturerDifferWrapper::OnDisplayChanged(
std::unique_ptr<DisplayList> displays) {
RTC_DCHECK(callback_);
callback_->OnDisplayChanged(std::move(displays));
}
} // namespace webrtc

View File

@ -55,6 +55,7 @@ class DesktopCapturerDifferWrapper : public DesktopCapturer,
// DesktopCapturer::Callback interface.
void OnCaptureResult(Result result,
std::unique_ptr<DesktopFrame> frame) override;
void OnDisplayChanged(std::unique_ptr<DisplayList> displays) override;
const std::unique_ptr<DesktopCapturer> base_capturer_;
DesktopCapturer::Callback* callback_;

View File

@ -179,4 +179,10 @@ void FallbackDesktopCapturerWrapper::OnCaptureResult(
secondary_capturer_->CaptureFrame();
}
void FallbackDesktopCapturerWrapper::OnDisplayChanged(
std::unique_ptr<DisplayList> displays) {
RTC_DCHECK(callback_);
callback_->OnDisplayChanged(std::move(displays));
}
} // namespace webrtc

View File

@ -51,6 +51,7 @@ class FallbackDesktopCapturerWrapper final : public DesktopCapturer,
// DesktopCapturer::Callback interface.
void OnCaptureResult(Result result,
std::unique_ptr<DesktopFrame> frame) override;
void OnDisplayChanged(std::unique_ptr<DisplayList> displays) override;
const std::unique_ptr<DesktopCapturer> main_capturer_;
const std::unique_ptr<DesktopCapturer> secondary_capturer_;

View File

@ -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

View File

@ -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_

View File

@ -108,6 +108,11 @@ void ScreenCapturerWinDirectx::Start(Callback* callback) {
RTC_DCHECK(callback);
callback_ = callback;
// Send initial desktop display summary.
auto displays = std::make_unique<DisplayList>();
if (GetDisplayList(displays.get()))
callback_->OnDisplayChanged(std::move(displays));
}
void ScreenCapturerWinDirectx::SetSharedMemoryFactory(

View File

@ -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<DisplayList>();
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);