Window capturer implementation for Windows.
R=alexeypa@chromium.org, andrew@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1477004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4064 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
5e2a1bbbc6
commit
b10ccbec02
@ -7,50 +7,79 @@
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'desktop_capture',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
# Headers may use include path relative to webrtc root and depend on
|
||||
# WEBRTC_WIN define, so we need to make sure dependent targets have
|
||||
# these settings.
|
||||
#
|
||||
# TODO(sergeyu): Move these settings to common.gypi
|
||||
'include_dirs': [
|
||||
'../../..',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'defines': [
|
||||
'WEBRTC_WIN',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
"desktop_capturer.h",
|
||||
"desktop_frame.cc",
|
||||
"desktop_frame.h",
|
||||
"desktop_frame_win.cc",
|
||||
"desktop_frame_win.h",
|
||||
"desktop_geometry.cc",
|
||||
"desktop_geometry.h",
|
||||
"desktop_region.cc",
|
||||
"desktop_region.h",
|
||||
"shared_memory.cc",
|
||||
"shared_memory.h",
|
||||
],
|
||||
'conditions': [
|
||||
['OS!="win"', {
|
||||
'sources/': [
|
||||
['exclude', '_win(_unittest)?\\.(cc|h)$'],
|
||||
'variables': {
|
||||
'conditions': [
|
||||
# Desktop capturer is supported only on Windows, OSX and Linux.
|
||||
['OS=="win" or OS=="mac" or OS=="linux"', {
|
||||
'desktop_capture_enabled%': 1,
|
||||
}, {
|
||||
'desktop_capture_enabled%': 0,
|
||||
}],
|
||||
],
|
||||
},
|
||||
'conditions': [
|
||||
['desktop_capture_enabled==1', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'desktop_capture',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
], # targets
|
||||
'direct_dependent_settings': {
|
||||
# Headers may use include path relative to webrtc root and depend on
|
||||
# WEBRTC_WIN define, so we need to make sure dependent targets have
|
||||
# these settings.
|
||||
#
|
||||
# TODO(sergeyu): Move these settings to common.gypi
|
||||
'include_dirs': [
|
||||
'../../..',
|
||||
],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'defines': [
|
||||
'WEBRTC_WIN',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
"desktop_capturer.h",
|
||||
"desktop_frame.cc",
|
||||
"desktop_frame.h",
|
||||
"desktop_frame_win.cc",
|
||||
"desktop_frame_win.h",
|
||||
"desktop_geometry.cc",
|
||||
"desktop_geometry.h",
|
||||
"desktop_region.cc",
|
||||
"desktop_region.h",
|
||||
"shared_memory.cc",
|
||||
"shared_memory.h",
|
||||
"window_capturer.h",
|
||||
"window_capturer_linux.cc",
|
||||
"window_capturer_mac.cc",
|
||||
"window_capturer_win.cc",
|
||||
],
|
||||
},
|
||||
], # targets
|
||||
}], # desktop_capture_enabled==1
|
||||
['desktop_capture_enabled==1 and include_tests==1', {
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'desktop_capture_unittests',
|
||||
'type': 'executable',
|
||||
'dependencies': [
|
||||
'desktop_capture',
|
||||
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||
'<(webrtc_root)/test/test.gyp:test_support',
|
||||
'<(webrtc_root)/test/test.gyp:test_support_main',
|
||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||
],
|
||||
'sources': [
|
||||
"window_capturer_unittest.cc",
|
||||
],
|
||||
},
|
||||
], # targets
|
||||
}], # desktop_capture_enabled==1 && include_tests==1
|
||||
],
|
||||
}
|
||||
|
55
webrtc/modules/desktop_capture/window_capturer.h
Normal file
55
webrtc/modules/desktop_capture/window_capturer.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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_WINDOW_CAPTURER_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_CAPTURER_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_capturer.h"
|
||||
#include "webrtc/system_wrappers/interface/constructor_magic.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class WindowCapturer : public DesktopCapturer {
|
||||
public:
|
||||
#if defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
|
||||
typedef unsigned int WindowId;
|
||||
#elif defined(WEBRTC_WIN)
|
||||
typedef void* WindowId;
|
||||
#endif
|
||||
|
||||
struct Window {
|
||||
WindowId id;
|
||||
|
||||
// Title of the window in UTF-8 encoding.
|
||||
std::string title;
|
||||
};
|
||||
|
||||
typedef std::vector<Window> WindowList;
|
||||
|
||||
static WindowCapturer* Create();
|
||||
|
||||
virtual ~WindowCapturer() {}
|
||||
|
||||
// Get list of windows. Returns false in case of a failure.
|
||||
virtual bool GetWindowList(WindowList* windows) = 0;
|
||||
|
||||
// Select window to be captured. Returns false in case of a failure (e.g. if
|
||||
// there is no window with the specified id).
|
||||
virtual bool SelectWindow(WindowId id) = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_CAPTURER_H_
|
||||
|
76
webrtc/modules/desktop_capture/window_capturer_linux.cc
Executable file
76
webrtc/modules/desktop_capture/window_capturer_linux.cc
Executable file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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/window_capturer.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
class WindowCapturerLinux : public WindowCapturer {
|
||||
public:
|
||||
WindowCapturerLinux();
|
||||
virtual ~WindowCapturerLinux();
|
||||
|
||||
// WindowCapturer interface.
|
||||
virtual bool GetWindowList(WindowList* windows) OVERRIDE;
|
||||
virtual bool SelectWindow(WindowId id) OVERRIDE;
|
||||
|
||||
// DesktopCapturer interface.
|
||||
virtual void Start(Callback* callback) OVERRIDE;
|
||||
virtual void Capture(const DesktopRegion& region) OVERRIDE;
|
||||
|
||||
private:
|
||||
Callback* callback_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux);
|
||||
};
|
||||
|
||||
WindowCapturerLinux::WindowCapturerLinux()
|
||||
: callback_(NULL) {
|
||||
}
|
||||
|
||||
WindowCapturerLinux::~WindowCapturerLinux() {
|
||||
}
|
||||
|
||||
bool WindowCapturerLinux::GetWindowList(WindowList* windows) {
|
||||
// Not implemented yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WindowCapturerLinux::SelectWindow(WindowId id) {
|
||||
// Not implemented yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
void WindowCapturerLinux::Start(Callback* callback) {
|
||||
assert(!callback_);
|
||||
assert(callback);
|
||||
|
||||
callback_ = callback;
|
||||
}
|
||||
|
||||
void WindowCapturerLinux::Capture(const DesktopRegion& region) {
|
||||
// Not implemented yet.
|
||||
callback_->OnCaptureCompleted(NULL);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
WindowCapturer* WindowCapturer::Create() {
|
||||
return new WindowCapturerLinux();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
76
webrtc/modules/desktop_capture/window_capturer_mac.cc
Executable file
76
webrtc/modules/desktop_capture/window_capturer_mac.cc
Executable file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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/window_capturer.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
class WindowCapturerMac : public WindowCapturer {
|
||||
public:
|
||||
WindowCapturerMac();
|
||||
virtual ~WindowCapturerMac();
|
||||
|
||||
// WindowCapturer interface.
|
||||
virtual bool GetWindowList(WindowList* windows) OVERRIDE;
|
||||
virtual bool SelectWindow(WindowId id) OVERRIDE;
|
||||
|
||||
// DesktopCapturer interface.
|
||||
virtual void Start(Callback* callback) OVERRIDE;
|
||||
virtual void Capture(const DesktopRegion& region) OVERRIDE;
|
||||
|
||||
private:
|
||||
Callback* callback_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac);
|
||||
};
|
||||
|
||||
WindowCapturerMac::WindowCapturerMac()
|
||||
: callback_(NULL) {
|
||||
}
|
||||
|
||||
WindowCapturerMac::~WindowCapturerMac() {
|
||||
}
|
||||
|
||||
bool WindowCapturerMac::GetWindowList(WindowList* windows) {
|
||||
// Not implemented yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WindowCapturerMac::SelectWindow(WindowId id) {
|
||||
// Not implemented yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
void WindowCapturerMac::Start(Callback* callback) {
|
||||
assert(!callback_);
|
||||
assert(callback);
|
||||
|
||||
callback_ = callback;
|
||||
}
|
||||
|
||||
void WindowCapturerMac::Capture(const DesktopRegion& region) {
|
||||
// Not implemented yet.
|
||||
callback_->OnCaptureCompleted(NULL);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
WindowCapturer* WindowCapturer::Create() {
|
||||
return new WindowCapturerMac();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
96
webrtc/modules/desktop_capture/window_capturer_unittest.cc
Normal file
96
webrtc/modules/desktop_capture/window_capturer_unittest.cc
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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/window_capturer.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_region.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class WindowCapturerTest : public testing::Test,
|
||||
public DesktopCapturer::Callback {
|
||||
public:
|
||||
void SetUp() OVERRIDE {
|
||||
capturer_.reset(WindowCapturer::Create());
|
||||
}
|
||||
|
||||
void TearDown() OVERRIDE {
|
||||
}
|
||||
|
||||
// DesktopCapturer::Callback interface
|
||||
virtual SharedMemory* CreateSharedMemory(size_t size) OVERRIDE {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual void OnCaptureCompleted(DesktopFrame* frame) OVERRIDE {
|
||||
frame_.reset(frame);
|
||||
}
|
||||
|
||||
protected:
|
||||
scoped_ptr<WindowCapturer> capturer_;
|
||||
scoped_ptr<DesktopFrame> frame_;
|
||||
};
|
||||
|
||||
// Verify that we can enumerate windows.
|
||||
TEST_F(WindowCapturerTest, Enumerate) {
|
||||
WindowCapturer::WindowList windows;
|
||||
EXPECT_TRUE(capturer_->GetWindowList(&windows));
|
||||
|
||||
// Assume that there is at least one window.
|
||||
EXPECT_GT(windows.size(), 0U);
|
||||
|
||||
// Verify that window titles are set.
|
||||
for (WindowCapturer::WindowList::iterator it = windows.begin();
|
||||
it != windows.end(); ++it) {
|
||||
EXPECT_FALSE(it->title.empty());
|
||||
}
|
||||
}
|
||||
|
||||
// Verify we can capture a window.
|
||||
//
|
||||
// TODO(sergeyu): Currently this test just looks at the windows that already
|
||||
// exist. Ideally it should create a test window and capture from it, but there
|
||||
// is no easy cross-platform way to create new windows (potentially we could
|
||||
// have a python script showing Tk dialog, but launching code will differ
|
||||
// between platforms).
|
||||
TEST_F(WindowCapturerTest, Capture) {
|
||||
WindowCapturer::WindowList windows;
|
||||
capturer_->Start(this);
|
||||
EXPECT_TRUE(capturer_->GetWindowList(&windows));
|
||||
|
||||
// Verify that we can select and capture each window.
|
||||
for (WindowCapturer::WindowList::iterator it = windows.begin();
|
||||
it != windows.end(); ++it) {
|
||||
frame_.reset();
|
||||
if (capturer_->SelectWindow(it->id)) {
|
||||
capturer_->Capture(DesktopRegion());
|
||||
}
|
||||
|
||||
// If we failed to capture a window make sure it no longer exists.
|
||||
if (!frame_.get()) {
|
||||
WindowCapturer::WindowList new_list;
|
||||
EXPECT_TRUE(capturer_->GetWindowList(&new_list));
|
||||
for (WindowCapturer::WindowList::iterator new_list_it = windows.begin();
|
||||
new_list_it != windows.end(); ++new_list_it) {
|
||||
EXPECT_FALSE(it->id == new_list_it->id);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
EXPECT_GT(frame_->size().width(), 0);
|
||||
EXPECT_GT(frame_->size().height(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
233
webrtc/modules/desktop_capture/window_capturer_win.cc
Normal file
233
webrtc/modules/desktop_capture/window_capturer_win.cc
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2013 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/window_capturer.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <windows.h>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef HRESULT (WINAPI *DwmIsCompositionEnabledFunc)(BOOL* enabled);
|
||||
|
||||
// Coverts a zero-terminated UTF-16 string to UTF-8. Returns an empty string if
|
||||
// error occurs.
|
||||
std::string Utf16ToUtf8(const WCHAR* str) {
|
||||
int len_utf8 = WideCharToMultiByte(CP_UTF8, 0, str, -1,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (len_utf8 <= 0)
|
||||
return std::string();
|
||||
std::string result(len_utf8, '\0');
|
||||
int rv = WideCharToMultiByte(CP_UTF8, 0, str, -1,
|
||||
&*(result.begin()), len_utf8, NULL, NULL);
|
||||
if (rv != len_utf8)
|
||||
assert(false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
|
||||
WindowCapturer::WindowList* list =
|
||||
reinterpret_cast<WindowCapturer::WindowList*>(param);
|
||||
|
||||
// Skip windows that are invisible, minimized, have no title, or are owned,
|
||||
// unless they have the app window style set.
|
||||
int len = GetWindowTextLength(hwnd);
|
||||
HWND owner = GetWindow(hwnd, GW_OWNER);
|
||||
LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
if (len == 0 || IsIconic(hwnd) || !IsWindowVisible(hwnd) ||
|
||||
(owner && !(exstyle & WS_EX_APPWINDOW))) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Skip the Program Manager window and the Start button.
|
||||
const size_t kClassLength = 256;
|
||||
WCHAR class_name[kClassLength];
|
||||
GetClassName(hwnd, class_name, kClassLength);
|
||||
// Skip Program Manager window and the Start button. This is the same logic
|
||||
// that's used in Win32WindowPicker in libjingle. Consider filtering other
|
||||
// windows as well (e.g. toolbars).
|
||||
if (wcscmp(class_name, L"Progman") == 0 || wcscmp(class_name, L"Button") == 0)
|
||||
return TRUE;
|
||||
|
||||
WindowCapturer::Window window;
|
||||
window.id = hwnd;
|
||||
|
||||
const size_t kTitleLength = 500;
|
||||
WCHAR window_title[kTitleLength];
|
||||
// Truncate the title if it's longer than kTitleLength.
|
||||
GetWindowText(hwnd, window_title, kTitleLength);
|
||||
window.title = Utf16ToUtf8(window_title);
|
||||
|
||||
// Skip windows when we failed to convert the title or it is empty.
|
||||
if (window.title.empty())
|
||||
return TRUE;
|
||||
|
||||
list->push_back(window);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
class WindowCapturerWin : public WindowCapturer {
|
||||
public:
|
||||
WindowCapturerWin();
|
||||
virtual ~WindowCapturerWin();
|
||||
|
||||
// WindowCapturer interface.
|
||||
virtual bool GetWindowList(WindowList* windows) OVERRIDE;
|
||||
virtual bool SelectWindow(WindowId id) OVERRIDE;
|
||||
|
||||
// DesktopCapturer interface.
|
||||
virtual void Start(Callback* callback) OVERRIDE;
|
||||
virtual void Capture(const DesktopRegion& region) OVERRIDE;
|
||||
|
||||
private:
|
||||
bool IsAeroEnabled();
|
||||
|
||||
Callback* callback_;
|
||||
|
||||
// HWND and HDC for the currently selected window or NULL if window is not
|
||||
// selected.
|
||||
HWND window_;
|
||||
HDC window_dc_;
|
||||
|
||||
// dwmapi.dll is used to determine if desktop compositing is enabled.
|
||||
HMODULE dwmapi_library_;
|
||||
DwmIsCompositionEnabledFunc is_composition_enabled_func_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WindowCapturerWin);
|
||||
};
|
||||
|
||||
WindowCapturerWin::WindowCapturerWin()
|
||||
: callback_(NULL),
|
||||
window_(NULL),
|
||||
window_dc_(NULL) {
|
||||
// Try to load dwmapi.dll dynamically since it is not available on XP.
|
||||
dwmapi_library_ = LoadLibrary(L"dwmapi.dll");
|
||||
if (dwmapi_library_) {
|
||||
is_composition_enabled_func_ =
|
||||
reinterpret_cast<DwmIsCompositionEnabledFunc>(
|
||||
GetProcAddress(dwmapi_library_, "DwmIsCompositionEnabled"));
|
||||
assert(is_composition_enabled_func_);
|
||||
} else {
|
||||
is_composition_enabled_func_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
WindowCapturerWin::~WindowCapturerWin() {
|
||||
if (dwmapi_library_)
|
||||
FreeLibrary(dwmapi_library_);
|
||||
}
|
||||
|
||||
bool WindowCapturerWin::IsAeroEnabled() {
|
||||
BOOL result = FALSE;
|
||||
if (is_composition_enabled_func_)
|
||||
is_composition_enabled_func_(&result);
|
||||
return result != FALSE;
|
||||
}
|
||||
|
||||
bool WindowCapturerWin::GetWindowList(WindowList* windows) {
|
||||
WindowList result;
|
||||
LPARAM param = reinterpret_cast<LPARAM>(&result);
|
||||
if (!EnumWindows(&WindowsEnumerationHandler, param))
|
||||
return false;
|
||||
windows->swap(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowCapturerWin::SelectWindow(WindowId id) {
|
||||
if (window_dc_)
|
||||
ReleaseDC(window_, window_dc_);
|
||||
|
||||
window_ = reinterpret_cast<HWND>(id);
|
||||
window_dc_ = GetWindowDC(window_);
|
||||
if (!window_dc_) {
|
||||
LOG(LS_WARNING) << "Failed to select window: " << GetLastError();
|
||||
window_ = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowCapturerWin::Start(Callback* callback) {
|
||||
assert(!callback_);
|
||||
assert(callback);
|
||||
|
||||
callback_ = callback;
|
||||
}
|
||||
|
||||
void WindowCapturerWin::Capture(const DesktopRegion& region) {
|
||||
if (!window_dc_) {
|
||||
LOG(LS_ERROR) << "Window hasn't been selected: " << GetLastError();
|
||||
callback_->OnCaptureCompleted(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(window_);
|
||||
|
||||
RECT rect;
|
||||
if (!GetWindowRect(window_, &rect)) {
|
||||
LOG(LS_WARNING) << "Failed to get window size: " << GetLastError();
|
||||
callback_->OnCaptureCompleted(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_ptr<DesktopFrameWin> frame(DesktopFrameWin::Create(
|
||||
DesktopSize(rect.right - rect.left, rect.bottom - rect.top),
|
||||
NULL, window_dc_));
|
||||
|
||||
HDC mem_dc = CreateCompatibleDC(window_dc_);
|
||||
SelectObject(mem_dc, frame->bitmap());
|
||||
BOOL result = FALSE;
|
||||
|
||||
// When desktop composition (Aero) is enabled each window is rendered to a
|
||||
// private buffer allowing BitBlt() to get the window content even if the
|
||||
// window is occluded. PrintWindow() is slower but lets rendering the window
|
||||
// contents to an off-screen device context when Aero is not available.
|
||||
// PrintWindow() is not supported by some applications.
|
||||
|
||||
// If Aero is enabled, we prefer BitBlt() because it's faster and avoids
|
||||
// window flickering. Otherwise, we prefer PrintWindow() because BitBlt() may
|
||||
// render occluding windows on top of the desired window.
|
||||
|
||||
if (!IsAeroEnabled())
|
||||
result = PrintWindow(window_, mem_dc, 0);
|
||||
|
||||
// Aero is enabled or PrintWindow() failed, use BitBlt.
|
||||
if (!result) {
|
||||
result = BitBlt(mem_dc, 0, 0, frame->size().width(), frame->size().height(),
|
||||
window_dc_, 0, 0, SRCCOPY);
|
||||
}
|
||||
|
||||
DeleteDC(mem_dc);
|
||||
|
||||
if (!result) {
|
||||
LOG(LS_ERROR) << "Both PrintWindow() and BitBlt() failed.";
|
||||
frame.reset();
|
||||
}
|
||||
|
||||
callback_->OnCaptureCompleted(frame.release());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
WindowCapturer* WindowCapturer::Create() {
|
||||
return new WindowCapturerWin();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
Loading…
x
Reference in New Issue
Block a user