Implement scaling detection in WindowCapturerWin
WindowCapturerWin wrongly calculate the image size if the application it target does not support high DPI. It causes part of the output frame black. See bug for details. Bug: webrtc:8112 Change-Id: I33c66dfa977ec08a29c56ff86ae37320b1459c87 Reviewed-on: https://chromium-review.googlesource.com/634383 Commit-Queue: Zijie He <zijiehe@chromium.org> Reviewed-by: Jamie Walch <jamiewalch@chromium.org> Cr-Commit-Position: refs/heads/master@{#19531}
This commit is contained in:
parent
eb442054ac
commit
af5686a229
@ -70,5 +70,10 @@ void DesktopRect::Extend(int32_t left_offset,
|
||||
bottom_ += bottom_offset;
|
||||
}
|
||||
|
||||
void DesktopRect::Scale(double horizontal, double vertical) {
|
||||
right_ += width() * (horizontal - 1);
|
||||
bottom_ += height() * (vertical - 1);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -142,6 +142,10 @@ class DesktopRect {
|
||||
int32_t right_offset,
|
||||
int32_t bottom_offset);
|
||||
|
||||
// Scales current DesktopRect. This function does not impact the |top_| and
|
||||
// |left_|.
|
||||
void Scale(double horizontal, double vertical);
|
||||
|
||||
private:
|
||||
DesktopRect(int32_t left, int32_t top, int32_t right, int32_t bottom)
|
||||
: left_(left), top_(top), right_(right), bottom_(bottom) {
|
||||
|
||||
@ -66,4 +66,41 @@ TEST(DesktopRectTest, EmptyRectUnionWithEmptyOne) {
|
||||
ASSERT_TRUE(rect.is_empty());
|
||||
}
|
||||
|
||||
TEST(DesktopRectTest, Scale) {
|
||||
DesktopRect rect = DesktopRect::MakeXYWH(100, 100, 100, 100);
|
||||
rect.Scale(1.1, 1.1);
|
||||
ASSERT_EQ(rect.top(), 100);
|
||||
ASSERT_EQ(rect.left(), 100);
|
||||
ASSERT_EQ(rect.width(), 110);
|
||||
ASSERT_EQ(rect.height(), 110);
|
||||
|
||||
rect = DesktopRect::MakeXYWH(100, 100, 100, 100);
|
||||
rect.Scale(0.01, 0.01);
|
||||
ASSERT_EQ(rect.top(), 100);
|
||||
ASSERT_EQ(rect.left(), 100);
|
||||
ASSERT_EQ(rect.width(), 1);
|
||||
ASSERT_EQ(rect.height(), 1);
|
||||
|
||||
rect = DesktopRect::MakeXYWH(100, 100, 100, 100);
|
||||
rect.Scale(1.1, 0.9);
|
||||
ASSERT_EQ(rect.top(), 100);
|
||||
ASSERT_EQ(rect.left(), 100);
|
||||
ASSERT_EQ(rect.width(), 110);
|
||||
ASSERT_EQ(rect.height(), 90);
|
||||
|
||||
rect = DesktopRect::MakeXYWH(0, 0, 100, 100);
|
||||
rect.Scale(1.1, 1.1);
|
||||
ASSERT_EQ(rect.top(), 0);
|
||||
ASSERT_EQ(rect.left(), 0);
|
||||
ASSERT_EQ(rect.width(), 110);
|
||||
ASSERT_EQ(rect.height(), 110);
|
||||
|
||||
rect = DesktopRect::MakeXYWH(0, 100, 100, 100);
|
||||
rect.Scale(1.1, 1.1);
|
||||
ASSERT_EQ(rect.top(), 100);
|
||||
ASSERT_EQ(rect.left(), 0);
|
||||
ASSERT_EQ(rect.width(), 110);
|
||||
ASSERT_EQ(rect.height(), 110);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -113,6 +113,18 @@ int GetWindowRegionTypeWithBoundary(HWND window, DesktopRect* result) {
|
||||
return region_type;
|
||||
}
|
||||
|
||||
bool GetDcSize(HDC hdc, DesktopSize* size) {
|
||||
win::ScopedGDIObject<HGDIOBJ, win::DeleteObjectTraits<HGDIOBJ>>
|
||||
scoped_hgdi(GetCurrentObject(hdc, OBJ_BITMAP));
|
||||
BITMAP bitmap;
|
||||
memset(&bitmap, 0, sizeof(BITMAP));
|
||||
if (GetObject(scoped_hgdi.Get(), sizeof(BITMAP), &bitmap) == 0) {
|
||||
return false;
|
||||
}
|
||||
size->set(bitmap.bmWidth, bitmap.bmHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
AeroChecker::AeroChecker() : dwmapi_library_(nullptr), func_(nullptr) {
|
||||
// Try to load dwmapi.dll dynamically since it is not available on XP.
|
||||
dwmapi_library_ = LoadLibrary(L"dwmapi.dll");
|
||||
|
||||
@ -41,6 +41,10 @@ bool GetWindowContentRect(HWND window, DesktopRect* result);
|
||||
// |window| if region type is SIMPLEREGION.
|
||||
int GetWindowRegionTypeWithBoundary(HWND window, DesktopRect* result);
|
||||
|
||||
// Retrieves the size of the |hdc|. This function returns false if native APIs
|
||||
// fail.
|
||||
bool GetDcSize(HDC hdc, DesktopSize* size);
|
||||
|
||||
typedef HRESULT (WINAPI *DwmIsCompositionEnabledFunc)(BOOL* enabled);
|
||||
class AeroChecker {
|
||||
public:
|
||||
|
||||
@ -172,10 +172,23 @@ void WindowCapturerWin::CaptureFrame() {
|
||||
return;
|
||||
}
|
||||
|
||||
DesktopRect original_rect;
|
||||
DesktopRect cropped_rect;
|
||||
// TODO(zijiehe): GetCroppedWindowRect() is not accurate, Windows won't draw
|
||||
// the content below the |window_| with PrintWindow() or BitBlt(). See bug
|
||||
// https://bugs.chromium.org/p/webrtc/issues/detail?id=8157.
|
||||
if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) {
|
||||
LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
|
||||
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Return a 1x1 black frame if the window is minimized or invisible, to match
|
||||
// behavior on mace. Window can be temporarily invisible during the
|
||||
// transition of full screen mode on/off.
|
||||
if (IsIconic(window_) || !IsWindowVisible(window_)) {
|
||||
if (original_rect.is_empty() ||
|
||||
IsIconic(window_) ||
|
||||
!IsWindowVisible(window_)) {
|
||||
std::unique_ptr<DesktopFrame> frame(
|
||||
new BasicDesktopFrame(DesktopSize(1, 1)));
|
||||
memset(frame->data(), 0, frame->stride() * frame->size().height());
|
||||
@ -186,14 +199,6 @@ void WindowCapturerWin::CaptureFrame() {
|
||||
return;
|
||||
}
|
||||
|
||||
DesktopRect original_rect;
|
||||
DesktopRect cropped_rect;
|
||||
if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) {
|
||||
LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
|
||||
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
HDC window_dc = GetWindowDC(window_);
|
||||
if (!window_dc) {
|
||||
LOG(LS_WARNING) << "Failed to get window DC: " << GetLastError();
|
||||
@ -201,6 +206,29 @@ void WindowCapturerWin::CaptureFrame() {
|
||||
return;
|
||||
}
|
||||
|
||||
DesktopSize window_dc_size;
|
||||
if (GetDcSize(window_dc, &window_dc_size)) {
|
||||
// The |window_dc_size| is used to detect the scaling of the original
|
||||
// window. If the application does not support high-DPI settings, it will
|
||||
// be scaled by Windows according to the scaling setting.
|
||||
// https://www.google.com/search?q=windows+scaling+settings&ie=UTF-8
|
||||
// So the size of the |window_dc|, i.e. the bitmap we can retrieve from
|
||||
// PrintWindow() or BitBlt() function, will be smaller than
|
||||
// |original_rect| and |cropped_rect|. Part of the captured desktop frame
|
||||
// will be black. See
|
||||
// bug https://bugs.chromium.org/p/webrtc/issues/detail?id=8112 for
|
||||
// details.
|
||||
|
||||
// If |window_dc_size| is smaller than |window_rect|, let's resize both
|
||||
// |original_rect| and |cropped_rect| according to the scaling factor.
|
||||
const double vertical_scale =
|
||||
static_cast<double>(window_dc_size.width()) / original_rect.width();
|
||||
const double horizontal_scale =
|
||||
static_cast<double>(window_dc_size.height()) / original_rect.height();
|
||||
original_rect.Scale(vertical_scale, horizontal_scale);
|
||||
cropped_rect.Scale(vertical_scale, horizontal_scale);
|
||||
}
|
||||
|
||||
std::unique_ptr<DesktopFrameWin> frame(
|
||||
DesktopFrameWin::Create(cropped_rect.size(), nullptr, window_dc));
|
||||
if (!frame.get()) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user