Revert 6048 "Implement the Windows screen capturer using the Mag..."
> Implement the Windows screen capturer using the Magnification API.
> The original ScreenCapturerWin is renamed ScreenCapturerWinGdi.
>
> BUG=2789
> TESTED=full desktop cast and single monitor cast works on win7 and win8 desktop mode. Have to use GDI capturer on win8 metro mode. Changing display configuration work on the fly.
> R=sergeyu@chromium.org, wez@chromium.org
>
> Review URL: https://webrtc-codereview.appspot.com/12149004
TBR=jiayl@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/15429005
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6052 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/desktop_capture/desktop_capture.gypi b/modules/desktop_capture/desktop_capture.gypi
index 6f4a083..5f96745 100644
--- a/modules/desktop_capture/desktop_capture.gypi
+++ b/modules/desktop_capture/desktop_capture.gypi
@@ -69,12 +69,6 @@
"win/scoped_gdi_object.h",
"win/scoped_thread_desktop.cc",
"win/scoped_thread_desktop.h",
- "win/screen_capturer_win_gdi.cc",
- "win/screen_capturer_win_gdi.h",
- "win/screen_capturer_win_magnifier.cc",
- "win/screen_capturer_win_magnifier.h",
- "win/screen_capture_utils.cc",
- "win/screen_capture_utils.h",
"win/window_capture_utils.cc",
"win/window_capture_utils.h",
"window_capturer.cc",
diff --git a/modules/desktop_capture/desktop_capture_options.cc b/modules/desktop_capture/desktop_capture_options.cc
index 105853b..26044e1 100644
--- a/modules/desktop_capture/desktop_capture_options.cc
+++ b/modules/desktop_capture/desktop_capture_options.cc
@@ -19,10 +19,6 @@
// XDamage is often broken, so don't use it by default.
use_update_notifications_ = false;
#endif
-
-#if defined(WEBRTC_WIN)
- allow_use_magnification_api_ = false;
-#endif
}
DesktopCaptureOptions::~DesktopCaptureOptions() {}
diff --git a/modules/desktop_capture/desktop_capture_options.h b/modules/desktop_capture/desktop_capture_options.h
index c01d3d2..2a188a0 100644
--- a/modules/desktop_capture/desktop_capture_options.h
+++ b/modules/desktop_capture/desktop_capture_options.h
@@ -66,15 +66,6 @@
disable_effects_ = disable_effects;
}
-#if defined(WEBRTC_WIN)
- bool allow_use_magnification_api() const {
- return allow_use_magnification_api_;
- }
- void set_allow_use_magnification_api(bool allow) {
- allow_use_magnification_api_ = allow;
- }
-#endif
-
private:
#if defined(USE_X11)
scoped_refptr<SharedXDisplay> x_display_;
@@ -83,10 +74,6 @@
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
#endif
-
-#if defined(WEBRTC_WIN)
- bool allow_use_magnification_api_;
-#endif
bool use_update_notifications_;
bool disable_effects_;
};
diff --git a/modules/desktop_capture/screen_capturer_unittest.cc b/modules/desktop_capture/screen_capturer_unittest.cc
index 50ff7a2..94c1f70 100644
--- a/modules/desktop_capture/screen_capturer_unittest.cc
+++ b/modules/desktop_capture/screen_capturer_unittest.cc
@@ -106,7 +106,7 @@
delete frame;
}
-#if defined(WEBRTC_WIN)
+#if defined(OS_WIN)
TEST_F(ScreenCapturerTest, UseSharedBuffers) {
DesktopFrame* frame = NULL;
@@ -129,20 +129,6 @@
delete frame;
}
-TEST_F(ScreenCapturerTest, UseMagnifier) {
- DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault());
- options.set_allow_use_magnification_api(true);
- capturer_.reset(ScreenCapturer::Create(options));
-
- DesktopFrame* frame = NULL;
- EXPECT_CALL(callback_, OnCaptureCompleted(_)).WillOnce(SaveArg<0>(&frame));
-
- capturer_->Start(&callback_);
- capturer_->Capture(DesktopRegion());
- ASSERT_TRUE(frame);
- delete frame;
-}
-
-#endif // defined(WEBRTC_WIN)
+#endif // defined(OS_WIN)
} // namespace webrtc
diff --git a/modules/desktop_capture/screen_capturer_win.cc b/modules/desktop_capture/screen_capturer_win.cc
index 5950795..fc6ce50 100644
--- a/modules/desktop_capture/screen_capturer_win.cc
+++ b/modules/desktop_capture/screen_capturer_win.cc
@@ -10,20 +10,451 @@
#include "webrtc/modules/desktop_capture/screen_capturer.h"
+#include <windows.h>
+
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
-#include "webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h"
-#include "webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h"
+#include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
+#include "webrtc/modules/desktop_capture/desktop_region.h"
+#include "webrtc/modules/desktop_capture/differ.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
+#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
+#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
+#include "webrtc/modules/desktop_capture/win/cursor.h"
+#include "webrtc/modules/desktop_capture/win/desktop.h"
+#include "webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
+#include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
namespace webrtc {
+namespace {
+
+// Constants from dwmapi.h.
+const UINT DWM_EC_DISABLECOMPOSITION = 0;
+const UINT DWM_EC_ENABLECOMPOSITION = 1;
+
+typedef HRESULT (WINAPI * DwmEnableCompositionFunc)(UINT);
+
+const wchar_t kDwmapiLibraryName[] = L"dwmapi.dll";
+
+// ScreenCapturerWin captures 32bit RGB using GDI.
+//
+// ScreenCapturerWin is double-buffered as required by ScreenCapturer.
+class ScreenCapturerWin : public ScreenCapturer {
+ public:
+ ScreenCapturerWin(const DesktopCaptureOptions& options);
+ virtual ~ScreenCapturerWin();
+
+ // Overridden from ScreenCapturer:
+ virtual void Start(Callback* callback) OVERRIDE;
+ virtual void Capture(const DesktopRegion& region) OVERRIDE;
+ virtual void SetMouseShapeObserver(
+ MouseShapeObserver* mouse_shape_observer) OVERRIDE;
+ virtual bool GetScreenList(ScreenList* screens) OVERRIDE;
+ virtual bool SelectScreen(ScreenId id) OVERRIDE;
+
+ private:
+ // Make sure that the device contexts match the screen configuration.
+ void PrepareCaptureResources();
+
+ // Captures the current screen contents into the current buffer. Returns true
+ // if succeeded.
+ bool CaptureImage();
+
+ // Capture the current cursor shape.
+ void CaptureCursor();
+
+ // Get the rect of the currently selected screen, relative to the primary
+ // display's top-left. If the screen is disabled or disconnected, or any error
+ // happens, an empty rect is returned.
+ DesktopRect GetScreenRect();
+
+ Callback* callback_;
+ MouseShapeObserver* mouse_shape_observer_;
+ ScreenId current_screen_id_;
+ std::wstring current_device_key_;
+
+ // A thread-safe list of invalid rectangles, and the size of the most
+ // recently captured screen.
+ ScreenCapturerHelper helper_;
+
+ // Snapshot of the last cursor bitmap we sent to the client. This is used
+ // to diff against the current cursor so we only send a cursor-change
+ // message when the shape has changed.
+ MouseCursorShape last_cursor_;
+
+ ScopedThreadDesktop desktop_;
+
+ // GDI resources used for screen capture.
+ HDC desktop_dc_;
+ HDC memory_dc_;
+
+ // Queue of the frames buffers.
+ ScreenCaptureFrameQueue queue_;
+
+ // Rectangle describing the bounds of the desktop device context, relative to
+ // the primary display's top-left.
+ DesktopRect desktop_dc_rect_;
+
+ // Class to calculate the difference between two screen bitmaps.
+ scoped_ptr<Differ> differ_;
+
+ HMODULE dwmapi_library_;
+ DwmEnableCompositionFunc composition_func_;
+
+ // Used to suppress duplicate logging of SetThreadExecutionState errors.
+ bool set_thread_execution_state_failed_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWin);
+};
+
+ScreenCapturerWin::ScreenCapturerWin(const DesktopCaptureOptions& options)
+ : callback_(NULL),
+ mouse_shape_observer_(NULL),
+ current_screen_id_(kFullDesktopScreenId),
+ desktop_dc_(NULL),
+ memory_dc_(NULL),
+ dwmapi_library_(NULL),
+ composition_func_(NULL),
+ set_thread_execution_state_failed_(false) {
+ if (options.disable_effects()) {
+ // Load dwmapi.dll dynamically since it is not available on XP.
+ if (!dwmapi_library_)
+ dwmapi_library_ = LoadLibrary(kDwmapiLibraryName);
+
+ if (dwmapi_library_) {
+ composition_func_ = reinterpret_cast<DwmEnableCompositionFunc>(
+ GetProcAddress(dwmapi_library_, "DwmEnableComposition"));
+ }
+ }
+}
+
+ScreenCapturerWin::~ScreenCapturerWin() {
+ if (desktop_dc_)
+ ReleaseDC(NULL, desktop_dc_);
+ if (memory_dc_)
+ DeleteDC(memory_dc_);
+
+ // Restore Aero.
+ if (composition_func_)
+ (*composition_func_)(DWM_EC_ENABLECOMPOSITION);
+
+ if (dwmapi_library_)
+ FreeLibrary(dwmapi_library_);
+}
+
+void ScreenCapturerWin::Capture(const DesktopRegion& region) {
+ TickTime capture_start_time = TickTime::Now();
+
+ queue_.MoveToNextFrame();
+
+ // Request that the system not power-down the system, or the display hardware.
+ if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) {
+ if (!set_thread_execution_state_failed_) {
+ set_thread_execution_state_failed_ = true;
+ LOG_F(LS_WARNING) << "Failed to make system & display power assertion: "
+ << GetLastError();
+ }
+ }
+
+ // Make sure the GDI capture resources are up-to-date.
+ PrepareCaptureResources();
+
+ // Copy screen bits to the current buffer.
+ if (!CaptureImage()) {
+ callback_->OnCaptureCompleted(NULL);
+ return;
+ }
+
+ const DesktopFrame* current_frame = queue_.current_frame();
+ const DesktopFrame* last_frame = queue_.previous_frame();
+ if (last_frame && last_frame->size().equals(current_frame->size())) {
+ // Make sure the differencer is set up correctly for these previous and
+ // current screens.
+ if (!differ_.get() ||
+ (differ_->width() != current_frame->size().width()) ||
+ (differ_->height() != current_frame->size().height()) ||
+ (differ_->bytes_per_row() != current_frame->stride())) {
+ differ_.reset(new Differ(current_frame->size().width(),
+ current_frame->size().height(),
+ DesktopFrame::kBytesPerPixel,
+ current_frame->stride()));
+ }
+
+ // Calculate difference between the two last captured frames.
+ DesktopRegion region;
+ differ_->CalcDirtyRegion(last_frame->data(), current_frame->data(),
+ ®ion);
+ helper_.InvalidateRegion(region);
+ } else {
+ // No previous frame is available, or the screen is resized. Invalidate the
+ // whole screen.
+ helper_.InvalidateScreen(current_frame->size());
+ }
+
+ helper_.set_size_most_recent(current_frame->size());
+
+ // Emit the current frame.
+ DesktopFrame* frame = queue_.current_frame()->Share();
+ frame->set_dpi(DesktopVector(
+ GetDeviceCaps(desktop_dc_, LOGPIXELSX),
+ GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
+ frame->mutable_updated_region()->Clear();
+ helper_.TakeInvalidRegion(frame->mutable_updated_region());
+ frame->set_capture_time_ms(
+ (TickTime::Now() - capture_start_time).Milliseconds());
+ callback_->OnCaptureCompleted(frame);
+
+ // Check for cursor shape update.
+ CaptureCursor();
+}
+
+void ScreenCapturerWin::SetMouseShapeObserver(
+ MouseShapeObserver* mouse_shape_observer) {
+ assert(!mouse_shape_observer_);
+ assert(mouse_shape_observer);
+
+ mouse_shape_observer_ = mouse_shape_observer;
+}
+
+bool ScreenCapturerWin::GetScreenList(ScreenList* screens) {
+ assert(screens->size() == 0);
+ BOOL enum_result = TRUE;
+ for (int device_index = 0; ; ++device_index) {
+ DISPLAY_DEVICE device;
+ device.cb = sizeof(device);
+ enum_result = EnumDisplayDevices(NULL, device_index, &device, 0);
+ // |enum_result| is 0 if we have enumerated all devices.
+ if (!enum_result)
+ break;
+
+ // We only care about active displays.
+ if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE))
+ continue;
+ Screen screen;
+ screen.id = device_index;
+ screens->push_back(screen);
+ }
+ return true;
+}
+
+bool ScreenCapturerWin::SelectScreen(ScreenId id) {
+ if (id == kFullDesktopScreenId) {
+ current_screen_id_ = id;
+ return true;
+ }
+ DISPLAY_DEVICE device;
+ device.cb = sizeof(device);
+ BOOL enum_result = EnumDisplayDevices(NULL, id, &device, 0);
+ if (!enum_result)
+ return false;
+
+ current_device_key_ = device.DeviceKey;
+ current_screen_id_ = id;
+ return true;
+}
+
+void ScreenCapturerWin::Start(Callback* callback) {
+ assert(!callback_);
+ assert(callback);
+
+ callback_ = callback;
+
+ // Vote to disable Aero composited desktop effects while capturing. Windows
+ // will restore Aero automatically if the process exits. This has no effect
+ // under Windows 8 or higher. See crbug.com/124018.
+ if (composition_func_)
+ (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
+}
+
+void ScreenCapturerWin::PrepareCaptureResources() {
+ // Switch to the desktop receiving user input if different from the current
+ // one.
+ scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
+ if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
+ // Release GDI resources otherwise SetThreadDesktop will fail.
+ if (desktop_dc_) {
+ ReleaseDC(NULL, desktop_dc_);
+ desktop_dc_ = NULL;
+ }
+
+ if (memory_dc_) {
+ DeleteDC(memory_dc_);
+ memory_dc_ = NULL;
+ }
+
+ // If SetThreadDesktop() fails, the thread is still assigned a desktop.
+ // So we can continue capture screen bits, just from the wrong desktop.
+ desktop_.SetThreadDesktop(input_desktop.release());
+
+ // Re-assert our vote to disable Aero.
+ // See crbug.com/124018 and crbug.com/129906.
+ if (composition_func_ != NULL) {
+ (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
+ }
+ }
+
+ // If the display bounds have changed then recreate GDI resources.
+ // TODO(wez): Also check for pixel format changes.
+ DesktopRect screen_rect(DesktopRect::MakeXYWH(
+ GetSystemMetrics(SM_XVIRTUALSCREEN),
+ GetSystemMetrics(SM_YVIRTUALSCREEN),
+ GetSystemMetrics(SM_CXVIRTUALSCREEN),
+ GetSystemMetrics(SM_CYVIRTUALSCREEN)));
+ if (!screen_rect.equals(desktop_dc_rect_)) {
+ if (desktop_dc_) {
+ ReleaseDC(NULL, desktop_dc_);
+ desktop_dc_ = NULL;
+ }
+ if (memory_dc_) {
+ DeleteDC(memory_dc_);
+ memory_dc_ = NULL;
+ }
+ desktop_dc_rect_ = DesktopRect();
+ }
+
+ if (desktop_dc_ == NULL) {
+ assert(memory_dc_ == NULL);
+
+ // Create GDI device contexts to capture from the desktop into memory.
+ desktop_dc_ = GetDC(NULL);
+ if (!desktop_dc_)
+ abort();
+ memory_dc_ = CreateCompatibleDC(desktop_dc_);
+ if (!memory_dc_)
+ abort();
+ desktop_dc_rect_ = screen_rect;
+
+ // Make sure the frame buffers will be reallocated.
+ queue_.Reset();
+
+ helper_.ClearInvalidRegion();
+ }
+}
+
+bool ScreenCapturerWin::CaptureImage() {
+ DesktopRect screen_rect = GetScreenRect();
+ if (screen_rect.is_empty())
+ return false;
+ DesktopSize size = screen_rect.size();
+ // If the current buffer is from an older generation then allocate a new one.
+ // Note that we can't reallocate other buffers at this point, since the caller
+ // may still be reading from them.
+ if (!queue_.current_frame() ||
+ !queue_.current_frame()->size().equals(size)) {
+ assert(desktop_dc_ != NULL);
+ assert(memory_dc_ != NULL);
+
+ size_t buffer_size = size.width() * size.height() *
+ DesktopFrame::kBytesPerPixel;
+ SharedMemory* shared_memory =
+ callback_->CreateSharedMemory(buffer_size);
+ scoped_ptr<DesktopFrameWin> buffer(
+ DesktopFrameWin::Create(size, shared_memory, desktop_dc_));
+ queue_.ReplaceCurrentFrame(buffer.release());
+ }
+
+ // Select the target bitmap into the memory dc and copy the rect from desktop
+ // to memory.
+ DesktopFrameWin* current = static_cast<DesktopFrameWin*>(
+ queue_.current_frame()->GetUnderlyingFrame());
+ HGDIOBJ previous_object = SelectObject(memory_dc_, current->bitmap());
+ if (previous_object != NULL) {
+ BitBlt(memory_dc_,
+ 0, 0, screen_rect.width(), screen_rect.height(),
+ desktop_dc_,
+ screen_rect.left(), screen_rect.top(),
+ SRCCOPY | CAPTUREBLT);
+
+ // Select back the previously selected object to that the device contect
+ // could be destroyed independently of the bitmap if needed.
+ SelectObject(memory_dc_, previous_object);
+ }
+ return true;
+}
+
+void ScreenCapturerWin::CaptureCursor() {
+ CURSORINFO cursor_info;
+ cursor_info.cbSize = sizeof(CURSORINFO);
+ if (!GetCursorInfo(&cursor_info)) {
+ LOG_F(LS_ERROR) << "Unable to get cursor info. Error = " << GetLastError();
+ return;
+ }
+
+ // Note that |cursor_info.hCursor| does not need to be freed.
+ scoped_ptr<MouseCursor> cursor_image(
+ CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor));
+ if (!cursor_image.get())
+ return;
+
+ scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape);
+ cursor->hotspot = cursor_image->hotspot();
+ cursor->size = cursor_image->image()->size();
+ uint8_t* current_row = cursor_image->image()->data();
+ for (int y = 0; y < cursor_image->image()->size().height(); ++y) {
+ cursor->data.append(current_row,
+ current_row + cursor_image->image()->size().width() *
+ DesktopFrame::kBytesPerPixel);
+ current_row += cursor_image->image()->stride();
+ }
+
+ // Compare the current cursor with the last one we sent to the client. If
+ // they're the same, then don't bother sending the cursor again.
+ if (last_cursor_.size.equals(cursor->size) &&
+ last_cursor_.hotspot.equals(cursor->hotspot) &&
+ last_cursor_.data == cursor->data) {
+ return;
+ }
+
+ LOG(LS_VERBOSE) << "Sending updated cursor: " << cursor->size.width() << "x"
+ << cursor->size.height();
+
+ // Record the last cursor image that we sent to the client.
+ last_cursor_ = *cursor;
+
+ if (mouse_shape_observer_)
+ mouse_shape_observer_->OnCursorShapeChanged(cursor.release());
+}
+
+DesktopRect ScreenCapturerWin::GetScreenRect() {
+ DesktopRect rect = desktop_dc_rect_;
+ if (current_screen_id_ == kFullDesktopScreenId)
+ return rect;
+
+ DISPLAY_DEVICE device;
+ device.cb = sizeof(device);
+ BOOL result = EnumDisplayDevices(NULL, current_screen_id_, &device, 0);
+ if (!result)
+ return DesktopRect();
+
+ // Verifies the device index still maps to the same display device. DeviceKey
+ // is documented as reserved, but it actually contains the registry key for
+ // the device and is unique for each monitor, while DeviceID is not.
+ if (current_device_key_ != device.DeviceKey)
+ return DesktopRect();
+
+ DEVMODE device_mode;
+ device_mode.dmSize = sizeof(device_mode);
+ device_mode.dmDriverExtra = 0;
+ result = EnumDisplaySettingsEx(
+ device.DeviceName, ENUM_CURRENT_SETTINGS, &device_mode, 0);
+ if (!result)
+ return DesktopRect();
+
+ rect = DesktopRect::MakeXYWH(device_mode.dmPosition.x,
+ device_mode.dmPosition.y,
+ device_mode.dmPelsWidth,
+ device_mode.dmPelsHeight);
+ return rect;
+}
+} // namespace
+
// static
ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
- scoped_ptr<ScreenCapturer> gdi_capturer(new ScreenCapturerWinGdi(options));
-
- if (options.allow_use_magnification_api())
- return new ScreenCapturerWinMagnifier(gdi_capturer.Pass());
-
- return gdi_capturer.release();
+ return new ScreenCapturerWin(options);
}
} // namespace webrtc
diff --git a/modules/desktop_capture/win/screen_capture_utils.cc b/modules/desktop_capture/win/screen_capture_utils.cc
deleted file mode 100644
index 4487e6d..0000000
--- a/modules/desktop_capture/win/screen_capture_utils.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
-
-#include <windows.h>
-
-namespace webrtc {
-
-bool GetScreenList(ScreenCapturer::ScreenList* screens) {
- assert(screens->size() == 0);
-
- BOOL enum_result = TRUE;
- for (int device_index = 0;; ++device_index) {
- DISPLAY_DEVICE device;
- device.cb = sizeof(device);
- enum_result = EnumDisplayDevices(NULL, device_index, &device, 0);
-
- // |enum_result| is 0 if we have enumerated all devices.
- if (!enum_result)
- break;
-
- // We only care about active displays.
- if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE))
- continue;
-
- ScreenCapturer::Screen screen;
- screen.id = device_index;
- screens->push_back(screen);
- }
- return true;
-}
-
-bool IsScreenValid(ScreenId screen, std::wstring* device_key) {
- if (screen == kFullDesktopScreenId) {
- *device_key = L"";
- return true;
- }
-
- DISPLAY_DEVICE device;
- device.cb = sizeof(device);
- BOOL enum_result = EnumDisplayDevices(NULL, screen, &device, 0);
- if (enum_result)
- *device_key = device.DeviceKey;
-
- return !!enum_result;
-}
-
-DesktopRect GetScreenRect(ScreenId screen, const std::wstring& device_key) {
- if (screen == kFullDesktopScreenId) {
- return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN),
- GetSystemMetrics(SM_YVIRTUALSCREEN),
- GetSystemMetrics(SM_CXVIRTUALSCREEN),
- GetSystemMetrics(SM_CYVIRTUALSCREEN));
- }
-
- DISPLAY_DEVICE device;
- device.cb = sizeof(device);
- BOOL result = EnumDisplayDevices(NULL, screen, &device, 0);
- if (!result)
- return DesktopRect();
-
- // Verifies the device index still maps to the same display device, to make
- // sure we are capturing the same device when devices are added or removed.
- // DeviceKey is documented as reserved, but it actually contains the registry
- // key for the device and is unique for each monitor, while DeviceID is not.
- if (device_key != device.DeviceKey)
- return DesktopRect();
-
- DEVMODE device_mode;
- device_mode.dmSize = sizeof(device_mode);
- device_mode.dmDriverExtra = 0;
- result = EnumDisplaySettingsEx(
- device.DeviceName, ENUM_CURRENT_SETTINGS, &device_mode, 0);
- if (!result)
- return DesktopRect();
-
- return DesktopRect::MakeXYWH(device_mode.dmPosition.x,
- device_mode.dmPosition.y,
- device_mode.dmPelsWidth,
- device_mode.dmPelsHeight);
-}
-
-} // namespace webrtc
diff --git a/modules/desktop_capture/win/screen_capture_utils.h b/modules/desktop_capture/win/screen_capture_utils.h
deleted file mode 100644
index 42473e0..0000000
--- a/modules/desktop_capture/win/screen_capture_utils.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURE_UTILS_H_
-#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURE_UTILS_H_
-
-#include "webrtc/modules/desktop_capture/screen_capturer.h"
-
-namespace webrtc {
-
-// Output the list of active screens into |screens|. Returns true if succeeded,
-// or false if it fails to enumerate the display devices.
-bool GetScreenList(ScreenCapturer::ScreenList* screens);
-
-// Returns true if |screen| is a valid screen. The screen device key is
-// returned through |device_key| if the screen is valid. The device key can be
-// used in GetScreenRect to verify the screen matches the previously obtained
-// id.
-bool IsScreenValid(ScreenId screen, std::wstring* device_key);
-
-// Get the rect of the screen identified by |screen|, relative to the primary
-// display's top-left. If the screen device key does not match |device_key|, or
-// the screen does not exist, or any error happens, an empty rect is returned.
-DesktopRect GetScreenRect(ScreenId screen, const std::wstring& device_key);
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURE_UTILS_H_
diff --git a/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/modules/desktop_capture/win/screen_capturer_win_gdi.cc
deleted file mode 100644
index 5ab2553..0000000
--- a/modules/desktop_capture/win/screen_capturer_win_gdi.cc
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h"
-
-#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
-#include "webrtc/modules/desktop_capture/desktop_frame.h"
-#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
-#include "webrtc/modules/desktop_capture/desktop_region.h"
-#include "webrtc/modules/desktop_capture/differ.h"
-#include "webrtc/modules/desktop_capture/mouse_cursor.h"
-#include "webrtc/modules/desktop_capture/win/cursor.h"
-#include "webrtc/modules/desktop_capture/win/desktop.h"
-#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
-#include "webrtc/system_wrappers/interface/logging.h"
-#include "webrtc/system_wrappers/interface/tick_util.h"
-
-namespace webrtc {
-
-namespace {
-
-// Constants from dwmapi.h.
-const UINT DWM_EC_DISABLECOMPOSITION = 0;
-const UINT DWM_EC_ENABLECOMPOSITION = 1;
-
-const wchar_t kDwmapiLibraryName[] = L"dwmapi.dll";
-
-} // namespace
-
-ScreenCapturerWinGdi::ScreenCapturerWinGdi(const DesktopCaptureOptions& options)
- : callback_(NULL),
- mouse_shape_observer_(NULL),
- current_screen_id_(kFullDesktopScreenId),
- desktop_dc_(NULL),
- memory_dc_(NULL),
- dwmapi_library_(NULL),
- composition_func_(NULL),
- set_thread_execution_state_failed_(false) {
- if (options.disable_effects()) {
- // Load dwmapi.dll dynamically since it is not available on XP.
- if (!dwmapi_library_)
- dwmapi_library_ = LoadLibrary(kDwmapiLibraryName);
-
- if (dwmapi_library_) {
- composition_func_ = reinterpret_cast<DwmEnableCompositionFunc>(
- GetProcAddress(dwmapi_library_, "DwmEnableComposition"));
- }
- }
-}
-
-ScreenCapturerWinGdi::~ScreenCapturerWinGdi() {
- if (desktop_dc_)
- ReleaseDC(NULL, desktop_dc_);
- if (memory_dc_)
- DeleteDC(memory_dc_);
-
- // Restore Aero.
- if (composition_func_)
- (*composition_func_)(DWM_EC_ENABLECOMPOSITION);
-
- if (dwmapi_library_)
- FreeLibrary(dwmapi_library_);
-}
-
-void ScreenCapturerWinGdi::Capture(const DesktopRegion& region) {
- TickTime capture_start_time = TickTime::Now();
-
- queue_.MoveToNextFrame();
-
- // Request that the system not power-down the system, or the display hardware.
- if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) {
- if (!set_thread_execution_state_failed_) {
- set_thread_execution_state_failed_ = true;
- LOG_F(LS_WARNING) << "Failed to make system & display power assertion: "
- << GetLastError();
- }
- }
-
- // Make sure the GDI capture resources are up-to-date.
- PrepareCaptureResources();
-
- if (!CaptureImage()) {
- callback_->OnCaptureCompleted(NULL);
- return;
- }
-
- const DesktopFrame* current_frame = queue_.current_frame();
- const DesktopFrame* last_frame = queue_.previous_frame();
- if (last_frame && last_frame->size().equals(current_frame->size())) {
- // Make sure the differencer is set up correctly for these previous and
- // current screens.
- if (!differ_.get() ||
- (differ_->width() != current_frame->size().width()) ||
- (differ_->height() != current_frame->size().height()) ||
- (differ_->bytes_per_row() != current_frame->stride())) {
- differ_.reset(new Differ(current_frame->size().width(),
- current_frame->size().height(),
- DesktopFrame::kBytesPerPixel,
- current_frame->stride()));
- }
-
- // Calculate difference between the two last captured frames.
- DesktopRegion region;
- differ_->CalcDirtyRegion(last_frame->data(), current_frame->data(),
- ®ion);
- helper_.InvalidateRegion(region);
- } else {
- // No previous frame is available, or the screen is resized. Invalidate the
- // whole screen.
- helper_.InvalidateScreen(current_frame->size());
- }
-
- helper_.set_size_most_recent(current_frame->size());
-
- // Emit the current frame.
- DesktopFrame* frame = queue_.current_frame()->Share();
- frame->set_dpi(DesktopVector(
- GetDeviceCaps(desktop_dc_, LOGPIXELSX),
- GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
- frame->mutable_updated_region()->Clear();
- helper_.TakeInvalidRegion(frame->mutable_updated_region());
- frame->set_capture_time_ms(
- (TickTime::Now() - capture_start_time).Milliseconds());
- callback_->OnCaptureCompleted(frame);
-
- // Check for cursor shape update.
- CaptureCursor();
-}
-
-void ScreenCapturerWinGdi::SetMouseShapeObserver(
- MouseShapeObserver* mouse_shape_observer) {
- assert(!mouse_shape_observer_);
- assert(mouse_shape_observer);
-
- mouse_shape_observer_ = mouse_shape_observer;
-}
-
-bool ScreenCapturerWinGdi::GetScreenList(ScreenList* screens) {
- return webrtc::GetScreenList(screens);
-}
-
-bool ScreenCapturerWinGdi::SelectScreen(ScreenId id) {
- bool valid = IsScreenValid(id, ¤t_device_key_);
- if (valid)
- current_screen_id_ = id;
- return valid;
-}
-
-void ScreenCapturerWinGdi::Start(Callback* callback) {
- assert(!callback_);
- assert(callback);
-
- callback_ = callback;
-
- // Vote to disable Aero composited desktop effects while capturing. Windows
- // will restore Aero automatically if the process exits. This has no effect
- // under Windows 8 or higher. See crbug.com/124018.
- if (composition_func_)
- (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
-}
-
-void ScreenCapturerWinGdi::PrepareCaptureResources() {
- // Switch to the desktop receiving user input if different from the current
- // one.
- scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
- if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
- // Release GDI resources otherwise SetThreadDesktop will fail.
- if (desktop_dc_) {
- ReleaseDC(NULL, desktop_dc_);
- desktop_dc_ = NULL;
- }
-
- if (memory_dc_) {
- DeleteDC(memory_dc_);
- memory_dc_ = NULL;
- }
-
- // If SetThreadDesktop() fails, the thread is still assigned a desktop.
- // So we can continue capture screen bits, just from the wrong desktop.
- desktop_.SetThreadDesktop(input_desktop.release());
-
- // Re-assert our vote to disable Aero.
- // See crbug.com/124018 and crbug.com/129906.
- if (composition_func_ != NULL) {
- (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
- }
- }
-
- // If the display bounds have changed then recreate GDI resources.
- // TODO(wez): Also check for pixel format changes.
- DesktopRect screen_rect(DesktopRect::MakeXYWH(
- GetSystemMetrics(SM_XVIRTUALSCREEN),
- GetSystemMetrics(SM_YVIRTUALSCREEN),
- GetSystemMetrics(SM_CXVIRTUALSCREEN),
- GetSystemMetrics(SM_CYVIRTUALSCREEN)));
- if (!screen_rect.equals(desktop_dc_rect_)) {
- if (desktop_dc_) {
- ReleaseDC(NULL, desktop_dc_);
- desktop_dc_ = NULL;
- }
- if (memory_dc_) {
- DeleteDC(memory_dc_);
- memory_dc_ = NULL;
- }
- desktop_dc_rect_ = DesktopRect();
- }
-
- if (desktop_dc_ == NULL) {
- assert(memory_dc_ == NULL);
-
- // Create GDI device contexts to capture from the desktop into memory.
- desktop_dc_ = GetDC(NULL);
- if (!desktop_dc_)
- abort();
- memory_dc_ = CreateCompatibleDC(desktop_dc_);
- if (!memory_dc_)
- abort();
-
- desktop_dc_rect_ = screen_rect;
-
- // Make sure the frame buffers will be reallocated.
- queue_.Reset();
-
- helper_.ClearInvalidRegion();
- }
-}
-
-bool ScreenCapturerWinGdi::CaptureImage() {
- DesktopRect screen_rect =
- GetScreenRect(current_screen_id_, current_device_key_);
- if (screen_rect.is_empty())
- return false;
-
- DesktopSize size = screen_rect.size();
- // If the current buffer is from an older generation then allocate a new one.
- // Note that we can't reallocate other buffers at this point, since the caller
- // may still be reading from them.
- if (!queue_.current_frame() ||
- !queue_.current_frame()->size().equals(screen_rect.size())) {
- assert(desktop_dc_ != NULL);
- assert(memory_dc_ != NULL);
-
- size_t buffer_size = size.width() * size.height() *
- DesktopFrame::kBytesPerPixel;
- SharedMemory* shared_memory = callback_->CreateSharedMemory(buffer_size);
-
- scoped_ptr<DesktopFrame> buffer;
- buffer.reset(
- DesktopFrameWin::Create(size, shared_memory, desktop_dc_));
- queue_.ReplaceCurrentFrame(buffer.release());
- }
-
- // Select the target bitmap into the memory dc and copy the rect from desktop
- // to memory.
- DesktopFrameWin* current = static_cast<DesktopFrameWin*>(
- queue_.current_frame()->GetUnderlyingFrame());
- HGDIOBJ previous_object = SelectObject(memory_dc_, current->bitmap());
- if (previous_object != NULL) {
- BitBlt(memory_dc_,
- 0, 0, screen_rect.width(), screen_rect.height(),
- desktop_dc_,
- screen_rect.left(), screen_rect.top(),
- SRCCOPY | CAPTUREBLT);
-
- // Select back the previously selected object to that the device contect
- // could be destroyed independently of the bitmap if needed.
- SelectObject(memory_dc_, previous_object);
- }
- return true;
-}
-
-void ScreenCapturerWinGdi::CaptureCursor() {
- CURSORINFO cursor_info;
- cursor_info.cbSize = sizeof(CURSORINFO);
- if (!GetCursorInfo(&cursor_info)) {
- LOG_F(LS_ERROR) << "Unable to get cursor info. Error = " << GetLastError();
- return;
- }
-
- // Note that |cursor_info.hCursor| does not need to be freed.
- scoped_ptr<MouseCursor> cursor_image(
- CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor));
- if (!cursor_image.get())
- return;
-
- scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape);
- cursor->hotspot = cursor_image->hotspot();
- cursor->size = cursor_image->image()->size();
- uint8_t* current_row = cursor_image->image()->data();
- for (int y = 0; y < cursor_image->image()->size().height(); ++y) {
- cursor->data.append(current_row,
- current_row + cursor_image->image()->size().width() *
- DesktopFrame::kBytesPerPixel);
- current_row += cursor_image->image()->stride();
- }
-
- // Compare the current cursor with the last one we sent to the client. If
- // they're the same, then don't bother sending the cursor again.
- if (last_cursor_.size.equals(cursor->size) &&
- last_cursor_.hotspot.equals(cursor->hotspot) &&
- last_cursor_.data == cursor->data) {
- return;
- }
-
- LOG(LS_VERBOSE) << "Sending updated cursor: " << cursor->size.width() << "x"
- << cursor->size.height();
-
- // Record the last cursor image that we sent to the client.
- last_cursor_ = *cursor;
-
- if (mouse_shape_observer_)
- mouse_shape_observer_->OnCursorShapeChanged(cursor.release());
-}
-
-} // namespace webrtc
diff --git a/modules/desktop_capture/win/screen_capturer_win_gdi.h b/modules/desktop_capture/win/screen_capturer_win_gdi.h
deleted file mode 100644
index 2db87d0..0000000
--- a/modules/desktop_capture/win/screen_capturer_win_gdi.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_GDI_H_
-#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_GDI_H_
-
-#include "webrtc/modules/desktop_capture/screen_capturer.h"
-
-#include <windows.h>
-
-#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
-#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
-#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
-#include "webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
-#include "webrtc/system_wrappers/interface/scoped_ptr.h"
-
-namespace webrtc {
-
-class Differ;
-class MouseShapeObserver;
-
-// ScreenCapturerWinGdi captures 32bit RGB using GDI.
-//
-// ScreenCapturerWinGdi is double-buffered as required by ScreenCapturer.
-class ScreenCapturerWinGdi : public ScreenCapturer {
- public:
- explicit ScreenCapturerWinGdi(const DesktopCaptureOptions& options);
- virtual ~ScreenCapturerWinGdi();
-
- // Overridden from ScreenCapturer:
- virtual void Start(Callback* callback) OVERRIDE;
- virtual void Capture(const DesktopRegion& region) OVERRIDE;
- virtual void SetMouseShapeObserver(
- MouseShapeObserver* mouse_shape_observer) OVERRIDE;
- virtual bool GetScreenList(ScreenList* screens) OVERRIDE;
- virtual bool SelectScreen(ScreenId id) OVERRIDE;
-
- private:
- typedef HRESULT (WINAPI * DwmEnableCompositionFunc)(UINT);
-
- // Make sure that the device contexts match the screen configuration.
- void PrepareCaptureResources();
-
- // Captures the current screen contents into the current buffer. Returns true
- // if succeeded.
- bool CaptureImage();
-
- // Capture the current cursor shape.
- void CaptureCursor();
-
- Callback* callback_;
- MouseShapeObserver* mouse_shape_observer_;
- ScreenId current_screen_id_;
- std::wstring current_device_key_;
-
- // A thread-safe list of invalid rectangles, and the size of the most
- // recently captured screen.
- ScreenCapturerHelper helper_;
-
- // Snapshot of the last cursor bitmap we sent to the client. This is used
- // to diff against the current cursor so we only send a cursor-change
- // message when the shape has changed.
- MouseCursorShape last_cursor_;
-
- ScopedThreadDesktop desktop_;
-
- // GDI resources used for screen capture.
- HDC desktop_dc_;
- HDC memory_dc_;
-
- // Queue of the frames buffers.
- ScreenCaptureFrameQueue queue_;
-
- // Rectangle describing the bounds of the desktop device context, relative to
- // the primary display's top-left.
- DesktopRect desktop_dc_rect_;
-
- // Class to calculate the difference between two screen bitmaps.
- scoped_ptr<Differ> differ_;
-
- HMODULE dwmapi_library_;
- DwmEnableCompositionFunc composition_func_;
-
- // Used to suppress duplicate logging of SetThreadExecutionState errors.
- bool set_thread_execution_state_failed_;
-
- DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinGdi);
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_GDI_H_
diff --git a/modules/desktop_capture/win/screen_capturer_win_magnifier.cc b/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
deleted file mode 100644
index 4ce0073..0000000
--- a/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h"
-
-#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
-#include "webrtc/modules/desktop_capture/desktop_frame.h"
-#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
-#include "webrtc/modules/desktop_capture/desktop_region.h"
-#include "webrtc/modules/desktop_capture/differ.h"
-#include "webrtc/modules/desktop_capture/mouse_cursor.h"
-#include "webrtc/modules/desktop_capture/win/cursor.h"
-#include "webrtc/modules/desktop_capture/win/desktop.h"
-#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
-#include "webrtc/system_wrappers/interface/logging.h"
-#include "webrtc/system_wrappers/interface/tick_util.h"
-
-namespace webrtc {
-
-// kMagnifierWindowClass has to be "Magnifier" according to the Magnification
-// API. The other strings can be anything.
-static LPCTSTR kMagnifierHostClass = L"ScreenCapturerWinMagnifierHost";
-static LPCTSTR kHostWindowName = L"MagnifierHost";
-static LPCTSTR kMagnifierWindowClass = L"Magnifier";
-static LPCTSTR kMagnifierWindowName = L"MagnifierWindow";
-
-Atomic32 ScreenCapturerWinMagnifier::tls_index_(TLS_OUT_OF_INDEXES);
-
-ScreenCapturerWinMagnifier::ScreenCapturerWinMagnifier(
- scoped_ptr<ScreenCapturer> fallback_capturer)
- : fallback_capturer_(fallback_capturer.Pass()),
- fallback_capturer_started_(false),
- callback_(NULL),
- current_screen_id_(kFullDesktopScreenId),
- excluded_window_(NULL),
- set_thread_execution_state_failed_(false),
- desktop_dc_(NULL),
- mag_lib_handle_(NULL),
- mag_initialize_func_(NULL),
- mag_uninitialize_func_(NULL),
- set_window_source_func_(NULL),
- set_window_filter_list_func_(NULL),
- set_image_scaling_callback_func_(NULL),
- host_window_(NULL),
- magnifier_window_(NULL),
- magnifier_initialized_(false),
- magnifier_capture_succeeded_(true) {
-}
-
-ScreenCapturerWinMagnifier::~ScreenCapturerWinMagnifier() {
- // DestroyWindow must be called before MagUninitialize. magnifier_window_ is
- // destroyed automatically when host_window_ is destroyed.
- if (host_window_)
- DestroyWindow(host_window_);
-
- if (magnifier_initialized_)
- mag_uninitialize_func_();
-
- if (mag_lib_handle_)
- FreeLibrary(mag_lib_handle_);
-
- if (desktop_dc_)
- ReleaseDC(NULL, desktop_dc_);
-}
-
-void ScreenCapturerWinMagnifier::Start(Callback* callback) {
- assert(!callback_);
- assert(callback);
- callback_ = callback;
-
- InitializeMagnifier();
-}
-
-void ScreenCapturerWinMagnifier::Capture(const DesktopRegion& region) {
- TickTime capture_start_time = TickTime::Now();
-
- queue_.MoveToNextFrame();
-
- // Request that the system not power-down the system, or the display hardware.
- if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) {
- if (!set_thread_execution_state_failed_) {
- set_thread_execution_state_failed_ = true;
- LOG_F(LS_WARNING) << "Failed to make system & display power assertion: "
- << GetLastError();
- }
- }
- // Switch to the desktop receiving user input if different from the current
- // one.
- scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
- if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
- // Release GDI resources otherwise SetThreadDesktop will fail.
- if (desktop_dc_) {
- ReleaseDC(NULL, desktop_dc_);
- desktop_dc_ = NULL;
- }
- // If SetThreadDesktop() fails, the thread is still assigned a desktop.
- // So we can continue capture screen bits, just from the wrong desktop.
- desktop_.SetThreadDesktop(input_desktop.release());
- }
-
- bool succeeded = false;
-
- // Do not try to use the magnfiier if it's capturing non-primary screen, or it
- // failed before.
- if (magnifier_initialized_ && IsCapturingPrimaryScreenOnly() &&
- magnifier_capture_succeeded_) {
- DesktopRect rect = GetScreenRect(current_screen_id_, current_device_key_);
- CreateCurrentFrameIfNecessary(rect.size());
-
- // CaptureImage may fail in some situations, e.g. windows8 metro mode.
- succeeded = CaptureImage(rect);
- }
-
- // Defer to the fallback capturer if magnifier capturer did not work.
- if (!succeeded) {
- LOG_F(LS_WARNING) << "Switching to the fallback screen capturer.";
- StartFallbackCapturer();
- fallback_capturer_->Capture(region);
- return;
- }
-
- const DesktopFrame* current_frame = queue_.current_frame();
- const DesktopFrame* last_frame = queue_.previous_frame();
- if (last_frame && last_frame->size().equals(current_frame->size())) {
- // Make sure the differencer is set up correctly for these previous and
- // current screens.
- if (!differ_.get() || (differ_->width() != current_frame->size().width()) ||
- (differ_->height() != current_frame->size().height()) ||
- (differ_->bytes_per_row() != current_frame->stride())) {
- differ_.reset(new Differ(current_frame->size().width(),
- current_frame->size().height(),
- DesktopFrame::kBytesPerPixel,
- current_frame->stride()));
- }
-
- // Calculate difference between the two last captured frames.
- DesktopRegion region;
- differ_->CalcDirtyRegion(
- last_frame->data(), current_frame->data(), ®ion);
- helper_.InvalidateRegion(region);
- } else {
- // No previous frame is available, or the screen is resized. Invalidate the
- // whole screen.
- helper_.InvalidateScreen(current_frame->size());
- }
-
- helper_.set_size_most_recent(current_frame->size());
-
- // Emit the current frame.
- DesktopFrame* frame = queue_.current_frame()->Share();
- frame->set_dpi(DesktopVector(GetDeviceCaps(desktop_dc_, LOGPIXELSX),
- GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
- frame->mutable_updated_region()->Clear();
- helper_.TakeInvalidRegion(frame->mutable_updated_region());
- frame->set_capture_time_ms(
- (TickTime::Now() - capture_start_time).Milliseconds());
- callback_->OnCaptureCompleted(frame);
-}
-
-void ScreenCapturerWinMagnifier::SetMouseShapeObserver(
- MouseShapeObserver* mouse_shape_observer) {
- assert(false); // NOTREACHED();
-}
-
-bool ScreenCapturerWinMagnifier::GetScreenList(ScreenList* screens) {
- return webrtc::GetScreenList(screens);
-}
-
-bool ScreenCapturerWinMagnifier::SelectScreen(ScreenId id) {
- bool valid = IsScreenValid(id, ¤t_device_key_);
-
- // Set current_screen_id_ even if the fallback capturer is being used, so we
- // can switch back to the magnifier when possible.
- if (valid)
- current_screen_id_ = id;
-
- if (fallback_capturer_started_)
- fallback_capturer_->SelectScreen(id);
-
- return valid;
-}
-
-void ScreenCapturerWinMagnifier::SetExcludedWindow(WindowId excluded_window) {
- excluded_window_ = (HWND)excluded_window;
- if (excluded_window_ && magnifier_initialized_) {
- set_window_filter_list_func_(
- magnifier_window_, MW_FILTERMODE_EXCLUDE, 1, &excluded_window_);
- }
-}
-
-bool ScreenCapturerWinMagnifier::CaptureImage(const DesktopRect& rect) {
- assert(magnifier_initialized_);
-
- // Set the magnifier control to cover the captured rect. The content of the
- // magnifier control will be the captured image.
- BOOL result = SetWindowPos(magnifier_window_,
- NULL,
- rect.left(), rect.top(),
- rect.width(), rect.height(),
- 0);
- if (!result) {
- LOG_F(LS_WARNING) << "Failed to call SetWindowPos: " << GetLastError()
- << ". Rect = {" << rect.left() << ", " << rect.top()
- << ", " << rect.right() << ", " << rect.bottom() << "}";
- return false;
- }
-
- magnifier_capture_succeeded_ = false;
-
- RECT native_rect = {rect.left(), rect.top(), rect.right(), rect.bottom()};
-
- // OnCaptured will be called via OnMagImageScalingCallback and fill in the
- // frame before set_window_source_func_ returns.
- result = set_window_source_func_(magnifier_window_, native_rect);
-
- if (!result) {
- LOG_F(LS_WARNING) << "Failed to call MagSetWindowSource: " << GetLastError()
- << ". Rect = {" << rect.left() << ", " << rect.top()
- << ", " << rect.right() << ", " << rect.bottom() << "}";
- return false;
- }
-
- return magnifier_capture_succeeded_;
-}
-
-BOOL ScreenCapturerWinMagnifier::OnMagImageScalingCallback(
- HWND hwnd,
- void* srcdata,
- MAGIMAGEHEADER srcheader,
- void* destdata,
- MAGIMAGEHEADER destheader,
- RECT unclipped,
- RECT clipped,
- HRGN dirty) {
- assert(tls_index_.Value() != TLS_OUT_OF_INDEXES);
-
- ScreenCapturerWinMagnifier* owner =
- reinterpret_cast<ScreenCapturerWinMagnifier*>(
- TlsGetValue(tls_index_.Value()));
-
- owner->OnCaptured(srcdata, srcheader);
-
- return TRUE;
-}
-
-bool ScreenCapturerWinMagnifier::InitializeMagnifier() {
- assert(!magnifier_initialized_);
-
- desktop_dc_ = GetDC(NULL);
-
- mag_lib_handle_ = LoadLibrary(L"Magnification.dll");
- if (!mag_lib_handle_)
- return false;
-
- // Initialize Magnification API function pointers.
- mag_initialize_func_ = reinterpret_cast<MagInitializeFunc>(
- GetProcAddress(mag_lib_handle_, "MagInitialize"));
- mag_uninitialize_func_ = reinterpret_cast<MagUninitializeFunc>(
- GetProcAddress(mag_lib_handle_, "MagUninitialize"));
- set_window_source_func_ = reinterpret_cast<MagSetWindowSourceFunc>(
- GetProcAddress(mag_lib_handle_, "MagSetWindowSource"));
- set_window_filter_list_func_ = reinterpret_cast<MagSetWindowFilterListFunc>(
- GetProcAddress(mag_lib_handle_, "MagSetWindowFilterList"));
- set_image_scaling_callback_func_ =
- reinterpret_cast<MagSetImageScalingCallbackFunc>(
- GetProcAddress(mag_lib_handle_, "MagSetImageScalingCallback"));
-
- if (!mag_initialize_func_ || !mag_uninitialize_func_ ||
- !set_window_source_func_ || !set_window_filter_list_func_ ||
- !set_image_scaling_callback_func_) {
- LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
- << "library functions missing.";
- return false;
- }
-
- BOOL result = mag_initialize_func_();
- if (!result) {
- LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
- << "error from MagInitialize " << GetLastError();
- return false;
- }
-
- HMODULE hInstance = NULL;
- result = GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
- GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
- reinterpret_cast<char*>(&DefWindowProc),
- &hInstance);
- if (!result) {
- mag_uninitialize_func_();
- LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
- << "error from GetModulehandleExA " << GetLastError();
- return false;
- }
-
- // Register the host window class. See the MSDN documentation of the
- // Magnification API for more infomation.
- WNDCLASSEX wcex = {};
- wcex.cbSize = sizeof(WNDCLASSEX);
- wcex.lpfnWndProc = &DefWindowProc;
- wcex.hInstance = hInstance;
- wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
- wcex.lpszClassName = kMagnifierHostClass;
-
- // Ignore the error which may happen when the class is already registered.
- RegisterClassEx(&wcex);
-
- // Create the host window.
- host_window_ = CreateWindowEx(WS_EX_LAYERED,
- kMagnifierHostClass,
- kHostWindowName,
- 0,
- 0, 0, 0, 0,
- NULL,
- NULL,
- hInstance,
- NULL);
- if (!host_window_) {
- mag_uninitialize_func_();
- LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
- << "error from creating host window " << GetLastError();
- return false;
- }
-
- // Create the magnifier control.
- magnifier_window_ = CreateWindow(kMagnifierWindowClass,
- kMagnifierWindowName,
- WS_CHILD | WS_VISIBLE,
- 0, 0, 0, 0,
- host_window_,
- NULL,
- hInstance,
- NULL);
- if (!magnifier_window_) {
- mag_uninitialize_func_();
- LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
- << "error from creating magnifier window "
- << GetLastError();
- return false;
- }
-
- // Hide the host window.
- ShowWindow(host_window_, SW_HIDE);
-
- // Set the scaling callback to receive captured image.
- result = set_image_scaling_callback_func_(
- magnifier_window_,
- &ScreenCapturerWinMagnifier::OnMagImageScalingCallback);
- if (!result) {
- mag_uninitialize_func_();
- LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
- << "error from MagSetImageScalingCallback "
- << GetLastError();
- return false;
- }
-
- if (excluded_window_) {
- result = set_window_filter_list_func_(
- magnifier_window_, MW_FILTERMODE_EXCLUDE, 1, &excluded_window_);
- if (!result) {
- mag_uninitialize_func_();
- LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
- << "error from MagSetWindowFilterList "
- << GetLastError();
- return false;
- }
- }
-
- if (tls_index_.Value() == TLS_OUT_OF_INDEXES) {
- // More than one threads may get here at the same time, but only one will
- // write to tls_index_ using CompareExchange.
- DWORD new_tls_index = TlsAlloc();
- if (!tls_index_.CompareExchange(new_tls_index, TLS_OUT_OF_INDEXES))
- TlsFree(new_tls_index);
- }
-
- assert(tls_index_.Value() != TLS_OUT_OF_INDEXES);
- TlsSetValue(tls_index_.Value(), this);
-
- magnifier_initialized_ = true;
- return true;
-}
-
-void ScreenCapturerWinMagnifier::OnCaptured(void* data,
- const MAGIMAGEHEADER& header) {
- DesktopFrame* current_frame = queue_.current_frame();
-
- // Verify the format.
- // TODO(jiayl): support capturing sources with pixel formats other than RGBA.
- int captured_bytes_per_pixel = header.cbSize / header.width / header.height;
- if (header.format != GUID_WICPixelFormat32bppRGBA ||
- header.width != static_cast<UINT>(current_frame->size().width()) ||
- header.height != static_cast<UINT>(current_frame->size().height()) ||
- header.stride != static_cast<UINT>(current_frame->stride()) ||
- captured_bytes_per_pixel != DesktopFrame::kBytesPerPixel) {
- LOG_F(LS_WARNING) << "Output format does not match the captured format: "
- << "width = " << header.width << ", "
- << "height = " << header.height << ", "
- << "stride = " << header.stride << ", "
- << "bpp = " << captured_bytes_per_pixel << ", "
- << "pixel format RGBA ? "
- << (header.format == GUID_WICPixelFormat32bppRGBA) << ".";
- return;
- }
-
- // Copy the data into the frame.
- current_frame->CopyPixelsFrom(
- reinterpret_cast<uint8_t*>(data),
- header.stride,
- DesktopRect::MakeXYWH(0, 0, header.width, header.height));
-
- magnifier_capture_succeeded_ = true;
-}
-
-void ScreenCapturerWinMagnifier::CreateCurrentFrameIfNecessary(
- const DesktopSize& size) {
- // If the current buffer is from an older generation then allocate a new one.
- // Note that we can't reallocate other buffers at this point, since the caller
- // may still be reading from them.
- if (!queue_.current_frame() || !queue_.current_frame()->size().equals(size)) {
- size_t buffer_size =
- size.width() * size.height() * DesktopFrame::kBytesPerPixel;
- SharedMemory* shared_memory = callback_->CreateSharedMemory(buffer_size);
-
- scoped_ptr<DesktopFrame> buffer;
- if (shared_memory) {
- buffer.reset(new SharedMemoryDesktopFrame(
- size, size.width() * DesktopFrame::kBytesPerPixel, shared_memory));
- } else {
- buffer.reset(new BasicDesktopFrame(size));
- }
- queue_.ReplaceCurrentFrame(buffer.release());
- }
-}
-
-bool ScreenCapturerWinMagnifier::IsCapturingPrimaryScreenOnly() const {
- if (current_screen_id_ != kFullDesktopScreenId)
- return current_screen_id_ == 0; // the primary screen is always '0'.
-
- return GetSystemMetrics(SM_CMONITORS) == 1;
-}
-
-void ScreenCapturerWinMagnifier::StartFallbackCapturer() {
- assert(fallback_capturer_);
- if (!fallback_capturer_started_) {
- fallback_capturer_started_ = true;
-
- fallback_capturer_->Start(callback_);
- fallback_capturer_->SelectScreen(current_screen_id_);
- }
-}
-
-} // namespace webrtc
diff --git a/modules/desktop_capture/win/screen_capturer_win_magnifier.h b/modules/desktop_capture/win/screen_capturer_win_magnifier.h
deleted file mode 100644
index 618386a..0000000
--- a/modules/desktop_capture/win/screen_capturer_win_magnifier.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_MAGNIFIER_H_
-#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_MAGNIFIER_H_
-
-#include <magnification.h>
-#include <wincodec.h>
-#include <windows.h>
-
-#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
-#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
-#include "webrtc/modules/desktop_capture/screen_capturer.h"
-#include "webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
-#include "webrtc/system_wrappers/interface/atomic32.h"
-#include "webrtc/system_wrappers/interface/constructor_magic.h"
-#include "webrtc/system_wrappers/interface/scoped_ptr.h"
-
-namespace webrtc {
-
-class DesktopFrame;
-class DesktopRect;
-class Differ;
-class MouseShapeObserver;
-
-// Captures the screen using the Magnification API to support window exclusion.
-// Each capturer must run on a dedicated thread because it uses thread local
-// storage for redirecting the library callback. Also the thread must have a UI
-// message loop to handle the window messages for the magnifier window.
-class ScreenCapturerWinMagnifier : public ScreenCapturer {
- public:
- // |fallback_capturer| will be used to capture the screen if a non-primary
- // screen is being captured, or the OS does not support Magnification API, or
- // the magnifier capturer fails (e.g. in Windows8 Metro mode).
- explicit ScreenCapturerWinMagnifier(
- scoped_ptr<ScreenCapturer> fallback_capturer);
- virtual ~ScreenCapturerWinMagnifier();
-
- // Overridden from ScreenCapturer:
- virtual void Start(Callback* callback) OVERRIDE;
- virtual void Capture(const DesktopRegion& region) OVERRIDE;
- virtual void SetMouseShapeObserver(
- MouseShapeObserver* mouse_shape_observer) OVERRIDE;
- virtual bool GetScreenList(ScreenList* screens) OVERRIDE;
- virtual bool SelectScreen(ScreenId id) OVERRIDE;
- virtual void SetExcludedWindow(WindowId window) OVERRIDE;
-
- private:
- typedef BOOL(WINAPI* MagImageScalingCallback)(HWND hwnd,
- void* srcdata,
- MAGIMAGEHEADER srcheader,
- void* destdata,
- MAGIMAGEHEADER destheader,
- RECT unclipped,
- RECT clipped,
- HRGN dirty);
- typedef BOOL(WINAPI* MagInitializeFunc)(void);
- typedef BOOL(WINAPI* MagUninitializeFunc)(void);
- typedef BOOL(WINAPI* MagSetWindowSourceFunc)(HWND hwnd, RECT rect);
- typedef BOOL(WINAPI* MagSetWindowFilterListFunc)(HWND hwnd,
- DWORD dwFilterMode,
- int count,
- HWND* pHWND);
- typedef BOOL(WINAPI* MagSetImageScalingCallbackFunc)(
- HWND hwnd,
- MagImageScalingCallback callback);
-
- static BOOL WINAPI OnMagImageScalingCallback(HWND hwnd,
- void* srcdata,
- MAGIMAGEHEADER srcheader,
- void* destdata,
- MAGIMAGEHEADER destheader,
- RECT unclipped,
- RECT clipped,
- HRGN dirty);
-
- // Captures the screen within |rect| in the desktop coordinates. Returns true
- // if succeeded.
- // It can only capture the primary screen for now. The magnification library
- // crashes under some screen configurations (e.g. secondary screen on top of
- // primary screen) if it tries to capture a non-primary screen. The caller
- // must make sure not calling it on non-primary screens.
- bool CaptureImage(const DesktopRect& rect);
-
- // Helper method for setting up the magnifier control. Returns true if
- // succeeded.
- bool InitializeMagnifier();
-
- // Called by OnMagImageScalingCallback to output captured data.
- void OnCaptured(void* data, const MAGIMAGEHEADER& header);
-
- // Makes sure the current frame exists and matches |size|.
- void CreateCurrentFrameIfNecessary(const DesktopSize& size);
-
- // Returns true if we are capturing the primary screen only.
- bool IsCapturingPrimaryScreenOnly() const;
-
- // Start the fallback capturer and select the screen.
- void StartFallbackCapturer();
-
- static Atomic32 tls_index_;
-
- scoped_ptr<ScreenCapturer> fallback_capturer_;
- bool fallback_capturer_started_;
- Callback* callback_;
- ScreenId current_screen_id_;
- std::wstring current_device_key_;
- HWND excluded_window_;
-
- // A thread-safe list of invalid rectangles, and the size of the most
- // recently captured screen.
- ScreenCapturerHelper helper_;
-
- // Queue of the frames buffers.
- ScreenCaptureFrameQueue queue_;
-
- // Class to calculate the difference between two screen bitmaps.
- scoped_ptr<Differ> differ_;
-
- // Used to suppress duplicate logging of SetThreadExecutionState errors.
- bool set_thread_execution_state_failed_;
-
- ScopedThreadDesktop desktop_;
-
- // Used for getting the screen dpi.
- HDC desktop_dc_;
-
- HMODULE mag_lib_handle_;
- MagInitializeFunc mag_initialize_func_;
- MagUninitializeFunc mag_uninitialize_func_;
- MagSetWindowSourceFunc set_window_source_func_;
- MagSetWindowFilterListFunc set_window_filter_list_func_;
- MagSetImageScalingCallbackFunc set_image_scaling_callback_func_;
-
- // The hidden window hosting the magnifier control.
- HWND host_window_;
- // The magnifier control that captures the screen.
- HWND magnifier_window_;
-
- // True if the magnifier control has been successfully initialized.
- bool magnifier_initialized_;
-
- // True if the last OnMagImageScalingCallback was called and handled
- // successfully. Reset at the beginning of each CaptureImage call.
- bool magnifier_capture_succeeded_;
-
- DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinMagnifier);
-};
-
-} // namespace webrtc
-
-#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_MAGNIFIER_H_