Add DesktopCaptureOptions class.

The new class is used to pass configuration parameters to screen/window
capturers. It also allows to share X Window connection between multiple
objects.

R=wez@chromium.org

Review URL: https://webrtc-codereview.appspot.com/2374004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4952 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
sergeyu@chromium.org
2013-10-12 22:40:05 +00:00
parent f53622d42e
commit 894e6fe9ea
19 changed files with 368 additions and 116 deletions

View File

@ -22,6 +22,9 @@
"desktop_frame_win.h", "desktop_frame_win.h",
"desktop_geometry.cc", "desktop_geometry.cc",
"desktop_geometry.h", "desktop_geometry.h",
"desktop_capture_options.h",
"desktop_capture_options.cc",
"desktop_capturer.h",
"desktop_region.cc", "desktop_region.cc",
"desktop_region.h", "desktop_region.h",
"differ.cc", "differ.cc",
@ -35,6 +38,7 @@
"mouse_cursor_shape.h", "mouse_cursor_shape.h",
"screen_capture_frame_queue.cc", "screen_capture_frame_queue.cc",
"screen_capture_frame_queue.h", "screen_capture_frame_queue.h",
"screen_capturer.cc",
"screen_capturer.h", "screen_capturer.h",
"screen_capturer_helper.cc", "screen_capturer_helper.cc",
"screen_capturer_helper.h", "screen_capturer_helper.h",
@ -52,10 +56,13 @@
"win/scoped_gdi_object.h", "win/scoped_gdi_object.h",
"win/scoped_thread_desktop.cc", "win/scoped_thread_desktop.cc",
"win/scoped_thread_desktop.h", "win/scoped_thread_desktop.h",
"window_capturer.cc",
"window_capturer.h", "window_capturer.h",
"window_capturer_mac.cc", "window_capturer_mac.cc",
"window_capturer_win.cc", "window_capturer_win.cc",
"window_capturer_x11.cc", "window_capturer_x11.cc",
"x11/shared_x_display.h",
"x11/shared_x_display.cc",
"x11/x_error_trap.cc", "x11/x_error_trap.cc",
"x11/x_error_trap.h", "x11/x_error_trap.h",
"x11/x_server_pixel_buffer.cc", "x11/x_server_pixel_buffer.cc",

View File

@ -0,0 +1,35 @@
/*
* 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/desktop_capture_options.h"
namespace webrtc {
DesktopCaptureOptions::DesktopCaptureOptions()
: use_update_notifications_(true),
disable_effects_(true) {
#if defined(USE_X11)
// XDamage is often broken, so don't use it by default.
use_update_notifications_ = false;
#endif
}
DesktopCaptureOptions::~DesktopCaptureOptions() {}
// static
DesktopCaptureOptions DesktopCaptureOptions::CreateDefault() {
DesktopCaptureOptions result;
#if defined(USE_X11)
result.set_x_display(SharedXDisplay::CreateDefault());
#endif
return result;
}
} // namespace webrtc

View File

@ -0,0 +1,65 @@
/*
* 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_DESKTOP_CAPTURE_OPTIONS_H_
#define WEBRTC_MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_OPTIONS_H_
#include "webrtc/system_wrappers/interface/constructor_magic.h"
#if defined(USE_X11)
#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
#endif
namespace webrtc {
// An object that stores initialization parameters for screen and window
// capturers.
class DesktopCaptureOptions {
public:
// Creates an empty Options instance (e.g. without X display).
DesktopCaptureOptions();
~DesktopCaptureOptions();
// Returns instance of DesktopCaptureOptions with default parameters. On Linux
// also initializes X window connection. x_display() will be set to null if
// X11 connection failed (e.g. DISPLAY isn't set).
static DesktopCaptureOptions CreateDefault();
#if defined(USE_X11)
SharedXDisplay* x_display() const { return x_display_; }
void set_x_display(scoped_refptr<SharedXDisplay> x_display) {
x_display_ = x_display;
}
#endif
// Flag indicating that the capturer should use screen change notifications.
// Enables/disables use of XDAMAGE in the X11 capturer.
bool use_update_notifications() const { return use_update_notifications_; }
void set_use_update_notifications(bool use_update_notifications) {
use_update_notifications_ = use_update_notifications;
}
// Flag indicating if desktop effects (e.g. Aero) should be disabled when the
// capturer is active. Currently used only on Windows.
bool disable_effects() const { return disable_effects_; }
void set_disable_effects(bool disable_effects) {
disable_effects_ = disable_effects;
}
private:
#if defined(USE_X11)
scoped_refptr<SharedXDisplay> x_display_;
#endif
bool use_update_notifications_;
bool disable_effects_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_OPTIONS_H_

View File

@ -0,0 +1,36 @@
/*
* 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/screen_capturer.h"
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
namespace webrtc {
ScreenCapturer* ScreenCapturer::Create() {
return Create(DesktopCaptureOptions::CreateDefault());
}
#if defined(WEBRTC_LINUX)
ScreenCapturer* ScreenCapturer::CreateWithXDamage(
bool use_update_notifications) {
DesktopCaptureOptions options;
options.set_use_update_notifications(use_update_notifications);
return Create(options);
}
#elif defined(WEBRTC_WIN)
ScreenCapturer* ScreenCapturer::CreateWithDisableAero(bool disable_effects) {
DesktopCaptureOptions options;
options.set_disable_effects(disable_effects);
return Create(options);
}
#endif
} // namespace webrtc

View File

@ -17,6 +17,7 @@
namespace webrtc { namespace webrtc {
class DesktopCaptureOptions;
struct MouseCursorShape; struct MouseCursorShape;
// Class used to capture video frames asynchronously. // Class used to capture video frames asynchronously.
@ -57,6 +58,10 @@ class ScreenCapturer : public DesktopCapturer {
virtual ~ScreenCapturer() {} virtual ~ScreenCapturer() {}
// Creates platform-specific capturer. // Creates platform-specific capturer.
//
// TODO(sergeyu): Remove all Create() methods except the first one.
// crbug.com/172183
static ScreenCapturer* Create(const DesktopCaptureOptions& options);
static ScreenCapturer* Create(); static ScreenCapturer* Create();
#if defined(WEBRTC_LINUX) #if defined(WEBRTC_LINUX)

View File

@ -21,6 +21,7 @@
#include <OpenGL/OpenGL.h> #include <OpenGL/OpenGL.h>
#include <sys/utsname.h> #include <sys/utsname.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.h"
#include "webrtc/modules/desktop_capture/desktop_geometry.h" #include "webrtc/modules/desktop_capture/desktop_geometry.h"
#include "webrtc/modules/desktop_capture/desktop_region.h" #include "webrtc/modules/desktop_capture/desktop_region.h"
@ -895,7 +896,7 @@ void ScreenCapturerMac::DisplaysReconfiguredCallback(
} // namespace } // namespace
// static // static
ScreenCapturer* ScreenCapturer::Create() { ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& context) {
scoped_ptr<ScreenCapturerMac> capturer(new ScreenCapturerMac()); scoped_ptr<ScreenCapturerMac> capturer(new ScreenCapturerMac());
if (!capturer->Init()) if (!capturer->Init())
capturer.reset(); capturer.reset();

View File

@ -13,20 +13,8 @@
namespace webrtc { namespace webrtc {
// static // static
ScreenCapturer* ScreenCapturer::Create() { ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
return NULL; return NULL;
} }
#if defined(OS_LINUX)
// static
ScreenCapturer* ScreenCapturer::CreateWithXDamage(bool use_x_damage) {
return NULL;
}
#elif defined(OS_WIN)
// static
ScreenCapturer* ScreenCapturer::CreateWithDisableAero(bool disable_aero) {
return NULL;
}
#endif // defined(OS_WIN)
} // namespace webrtc } // namespace webrtc

View File

@ -12,6 +12,7 @@
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.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.h"
#include "webrtc/modules/desktop_capture/desktop_region.h" #include "webrtc/modules/desktop_capture/desktop_region.h"
#include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" #include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h"
@ -29,6 +30,11 @@ class ScreenCapturerTest : public testing::Test {
public: public:
SharedMemory* CreateSharedMemory(size_t size); SharedMemory* CreateSharedMemory(size_t size);
virtual void SetUp() OVERRIDE {
capturer_.reset(
ScreenCapturer::Create(DesktopCaptureOptions::CreateDefault()));
}
protected: protected:
scoped_ptr<ScreenCapturer> capturer_; scoped_ptr<ScreenCapturer> capturer_;
MockMouseShapeObserver mouse_observer_; MockMouseShapeObserver mouse_observer_;
@ -54,7 +60,6 @@ SharedMemory* ScreenCapturerTest::CreateSharedMemory(size_t size) {
} }
TEST_F(ScreenCapturerTest, StartCapturer) { TEST_F(ScreenCapturerTest, StartCapturer) {
capturer_.reset(ScreenCapturer::Create());
capturer_->SetMouseShapeObserver(&mouse_observer_); capturer_->SetMouseShapeObserver(&mouse_observer_);
capturer_->Start(&callback_); capturer_->Start(&callback_);
} }
@ -71,7 +76,6 @@ TEST_F(ScreenCapturerTest, Capture) {
.Times(AnyNumber()) .Times(AnyNumber())
.WillRepeatedly(Return(static_cast<SharedMemory*>(NULL))); .WillRepeatedly(Return(static_cast<SharedMemory*>(NULL)));
capturer_.reset(ScreenCapturer::Create());
capturer_->Start(&callback_); capturer_->Start(&callback_);
capturer_->Capture(DesktopRegion()); capturer_->Capture(DesktopRegion());
@ -106,7 +110,6 @@ TEST_F(ScreenCapturerTest, UseSharedBuffers) {
.Times(AnyNumber()) .Times(AnyNumber())
.WillRepeatedly(Invoke(this, &ScreenCapturerTest::CreateSharedMemory)); .WillRepeatedly(Invoke(this, &ScreenCapturerTest::CreateSharedMemory));
capturer_.reset(ScreenCapturer::Create());
capturer_->Start(&callback_); capturer_->Start(&callback_);
capturer_->Capture(DesktopRegion()); capturer_->Capture(DesktopRegion());

View File

@ -12,6 +12,7 @@
#include <windows.h> #include <windows.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.h"
#include "webrtc/modules/desktop_capture/desktop_frame_win.h" #include "webrtc/modules/desktop_capture/desktop_frame_win.h"
#include "webrtc/modules/desktop_capture/desktop_region.h" #include "webrtc/modules/desktop_capture/desktop_region.h"
@ -43,7 +44,7 @@ const wchar_t kDwmapiLibraryName[] = L"dwmapi.dll";
// ScreenCapturerWin is double-buffered as required by ScreenCapturer. // ScreenCapturerWin is double-buffered as required by ScreenCapturer.
class ScreenCapturerWin : public ScreenCapturer { class ScreenCapturerWin : public ScreenCapturer {
public: public:
ScreenCapturerWin(bool disable_aero); ScreenCapturerWin(const DesktopCaptureOptions& options);
virtual ~ScreenCapturerWin(); virtual ~ScreenCapturerWin();
// Overridden from ScreenCapturer: // Overridden from ScreenCapturer:
@ -98,7 +99,7 @@ class ScreenCapturerWin : public ScreenCapturer {
DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWin); DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWin);
}; };
ScreenCapturerWin::ScreenCapturerWin(bool disable_aero) ScreenCapturerWin::ScreenCapturerWin(const DesktopCaptureOptions& options)
: callback_(NULL), : callback_(NULL),
mouse_shape_observer_(NULL), mouse_shape_observer_(NULL),
desktop_dc_(NULL), desktop_dc_(NULL),
@ -106,7 +107,7 @@ ScreenCapturerWin::ScreenCapturerWin(bool disable_aero)
dwmapi_library_(NULL), dwmapi_library_(NULL),
composition_func_(NULL), composition_func_(NULL),
set_thread_execution_state_failed_(false) { set_thread_execution_state_failed_(false) {
if (disable_aero) { if (options.disable_effects()) {
// Load dwmapi.dll dynamically since it is not available on XP. // Load dwmapi.dll dynamically since it is not available on XP.
if (!dwmapi_library_) if (!dwmapi_library_)
dwmapi_library_ = LoadLibrary(kDwmapiLibraryName); dwmapi_library_ = LoadLibrary(kDwmapiLibraryName);
@ -353,13 +354,8 @@ void ScreenCapturerWin::CaptureCursor() {
} // namespace } // namespace
// static // static
ScreenCapturer* ScreenCapturer::Create() { ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
return CreateWithDisableAero(true); return new ScreenCapturerWin(options);
}
// static
ScreenCapturer* ScreenCapturer::CreateWithDisableAero(bool disable_aero) {
return new ScreenCapturerWin(disable_aero);
} }
} // namespace webrtc } // namespace webrtc

View File

@ -18,6 +18,7 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.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.h"
#include "webrtc/modules/desktop_capture/differ.h" #include "webrtc/modules/desktop_capture/differ.h"
#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h" #include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
@ -46,7 +47,7 @@ class ScreenCapturerLinux : public ScreenCapturer {
virtual ~ScreenCapturerLinux(); virtual ~ScreenCapturerLinux();
// TODO(ajwong): Do we really want this to be synchronous? // TODO(ajwong): Do we really want this to be synchronous?
bool Init(bool use_x_damage); bool Init(const DesktopCaptureOptions& options);
// DesktopCapturer interface. // DesktopCapturer interface.
virtual void Start(Callback* delegate) OVERRIDE; virtual void Start(Callback* delegate) OVERRIDE;
@ -57,6 +58,8 @@ class ScreenCapturerLinux : public ScreenCapturer {
MouseShapeObserver* mouse_shape_observer) OVERRIDE; MouseShapeObserver* mouse_shape_observer) OVERRIDE;
private: private:
Display* display() { return options_.x_display()->display(); }
void InitXDamage(); void InitXDamage();
// Read and handle all currently-pending XEvents. // Read and handle all currently-pending XEvents.
@ -88,11 +91,12 @@ class ScreenCapturerLinux : public ScreenCapturer {
void DeinitXlib(); void DeinitXlib();
DesktopCaptureOptions options_;
Callback* callback_; Callback* callback_;
MouseShapeObserver* mouse_shape_observer_; MouseShapeObserver* mouse_shape_observer_;
// X11 graphics context. // X11 graphics context.
Display* display_;
GC gc_; GC gc_;
Window root_window_; Window root_window_;
@ -131,7 +135,6 @@ class ScreenCapturerLinux : public ScreenCapturer {
ScreenCapturerLinux::ScreenCapturerLinux() ScreenCapturerLinux::ScreenCapturerLinux()
: callback_(NULL), : callback_(NULL),
mouse_shape_observer_(NULL), mouse_shape_observer_(NULL),
display_(NULL),
gc_(NULL), gc_(NULL),
root_window_(BadValue), root_window_(BadValue),
has_xfixes_(false), has_xfixes_(false),
@ -149,23 +152,17 @@ ScreenCapturerLinux::~ScreenCapturerLinux() {
DeinitXlib(); DeinitXlib();
} }
bool ScreenCapturerLinux::Init(bool use_x_damage) { bool ScreenCapturerLinux::Init(const DesktopCaptureOptions& options) {
// TODO(ajwong): We should specify the display string we are attaching to options_ = options;
// in the constructor.
display_ = XOpenDisplay(NULL);
if (!display_) {
LOG(LS_ERROR) << "Unable to open display";
return false;
}
root_window_ = RootWindow(display_, DefaultScreen(display_)); root_window_ = RootWindow(display(), DefaultScreen(display()));
if (root_window_ == BadValue) { if (root_window_ == BadValue) {
LOG(LS_ERROR) << "Unable to get the root window"; LOG(LS_ERROR) << "Unable to get the root window";
DeinitXlib(); DeinitXlib();
return false; return false;
} }
gc_ = XCreateGC(display_, root_window_, 0, NULL); gc_ = XCreateGC(display(), root_window_, 0, NULL);
if (gc_ == NULL) { if (gc_ == NULL) {
LOG(LS_ERROR) << "Unable to get graphics context"; LOG(LS_ERROR) << "Unable to get graphics context";
DeinitXlib(); DeinitXlib();
@ -174,7 +171,7 @@ bool ScreenCapturerLinux::Init(bool use_x_damage) {
// Check for XFixes extension. This is required for cursor shape // Check for XFixes extension. This is required for cursor shape
// notifications, and for our use of XDamage. // notifications, and for our use of XDamage.
if (XFixesQueryExtension(display_, &xfixes_event_base_, if (XFixesQueryExtension(display(), &xfixes_event_base_,
&xfixes_error_base_)) { &xfixes_error_base_)) {
has_xfixes_ = true; has_xfixes_ = true;
} else { } else {
@ -182,20 +179,20 @@ bool ScreenCapturerLinux::Init(bool use_x_damage) {
} }
// Register for changes to the dimensions of the root window. // Register for changes to the dimensions of the root window.
XSelectInput(display_, root_window_, StructureNotifyMask); XSelectInput(display(), root_window_, StructureNotifyMask);
if (!x_server_pixel_buffer_.Init(display_, DefaultRootWindow(display_))) { if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) {
LOG(LS_ERROR) << "Failed to initialize pixel buffer."; LOG(LS_ERROR) << "Failed to initialize pixel buffer.";
return false; return false;
} }
if (has_xfixes_) { if (has_xfixes_) {
// Register for changes to the cursor shape. // Register for changes to the cursor shape.
XFixesSelectCursorInput(display_, root_window_, XFixesSelectCursorInput(display(), root_window_,
XFixesDisplayCursorNotifyMask); XFixesDisplayCursorNotifyMask);
} }
if (use_x_damage) { if (options_.use_update_notifications()) {
InitXDamage(); InitXDamage();
} }
@ -209,7 +206,7 @@ void ScreenCapturerLinux::InitXDamage() {
} }
// Check for XDamage extension. // Check for XDamage extension.
if (!XDamageQueryExtension(display_, &damage_event_base_, if (!XDamageQueryExtension(display(), &damage_event_base_,
&damage_error_base_)) { &damage_error_base_)) {
LOG(LS_INFO) << "X server does not support XDamage."; LOG(LS_INFO) << "X server does not support XDamage.";
return; return;
@ -221,7 +218,7 @@ void ScreenCapturerLinux::InitXDamage() {
// properly. // properly.
// Request notifications every time the screen becomes damaged. // Request notifications every time the screen becomes damaged.
damage_handle_ = XDamageCreate(display_, root_window_, damage_handle_ = XDamageCreate(display(), root_window_,
XDamageReportNonEmpty); XDamageReportNonEmpty);
if (!damage_handle_) { if (!damage_handle_) {
LOG(LS_ERROR) << "Unable to initialize XDamage."; LOG(LS_ERROR) << "Unable to initialize XDamage.";
@ -229,9 +226,9 @@ void ScreenCapturerLinux::InitXDamage() {
} }
// Create an XFixes server-side region to collate damage into. // Create an XFixes server-side region to collate damage into.
damage_region_ = XFixesCreateRegion(display_, 0, 0); damage_region_ = XFixesCreateRegion(display(), 0, 0);
if (!damage_region_) { if (!damage_region_) {
XDamageDestroy(display_, damage_handle_); XDamageDestroy(display(), damage_handle_);
LOG(LS_ERROR) << "Unable to create XFixes region."; LOG(LS_ERROR) << "Unable to create XFixes region.";
return; return;
} }
@ -303,11 +300,11 @@ void ScreenCapturerLinux::SetMouseShapeObserver(
void ScreenCapturerLinux::ProcessPendingXEvents() { void ScreenCapturerLinux::ProcessPendingXEvents() {
// Find the number of events that are outstanding "now." We don't just loop // Find the number of events that are outstanding "now." We don't just loop
// on XPending because we want to guarantee this terminates. // on XPending because we want to guarantee this terminates.
int events_to_process = XPending(display_); int events_to_process = XPending(display());
XEvent e; XEvent e;
for (int i = 0; i < events_to_process; i++) { for (int i = 0; i < events_to_process; i++) {
XNextEvent(display_, &e); XNextEvent(display(), &e);
if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) { if (use_damage_ && (e.type == damage_event_base_ + XDamageNotify)) {
XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e); XDamageNotifyEvent* event = reinterpret_cast<XDamageNotifyEvent*>(&e);
DCHECK(event->level == XDamageReportNonEmpty); DCHECK(event->level == XDamageReportNonEmpty);
@ -329,7 +326,7 @@ void ScreenCapturerLinux::ProcessPendingXEvents() {
void ScreenCapturerLinux::CaptureCursor() { void ScreenCapturerLinux::CaptureCursor() {
DCHECK(has_xfixes_); DCHECK(has_xfixes_);
XFixesCursorImage* img = XFixesGetCursorImage(display_); XFixesCursorImage* img = XFixesGetCursorImage(display());
if (!img) { if (!img) {
return; return;
} }
@ -375,10 +372,10 @@ DesktopFrame* ScreenCapturerLinux::CaptureScreen() {
x_server_pixel_buffer_.Synchronize(); x_server_pixel_buffer_.Synchronize();
if (use_damage_ && queue_.previous_frame()) { if (use_damage_ && queue_.previous_frame()) {
// Atomically fetch and clear the damage region. // Atomically fetch and clear the damage region.
XDamageSubtract(display_, damage_handle_, None, damage_region_); XDamageSubtract(display(), damage_handle_, None, damage_region_);
int rects_num = 0; int rects_num = 0;
XRectangle bounds; XRectangle bounds;
XRectangle* rects = XFixesFetchRegionAndBounds(display_, damage_region_, XRectangle* rects = XFixesFetchRegionAndBounds(display(), damage_region_,
&rects_num, &bounds); &rects_num, &bounds);
for (int i = 0; i < rects_num; ++i) { for (int i = 0; i < rects_num; ++i) {
updated_region->AddRect(DesktopRect::MakeXYWH( updated_region->AddRect(DesktopRect::MakeXYWH(
@ -430,7 +427,7 @@ void ScreenCapturerLinux::ScreenConfigurationChanged() {
queue_.Reset(); queue_.Reset();
helper_.ClearInvalidRegion(); helper_.ClearInvalidRegion();
if (!x_server_pixel_buffer_.Init(display_, DefaultRootWindow(display_))) { if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) {
LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen " LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen "
"configuration change."; "configuration change.";
} }
@ -465,38 +462,34 @@ void ScreenCapturerLinux::SynchronizeFrame() {
void ScreenCapturerLinux::DeinitXlib() { void ScreenCapturerLinux::DeinitXlib() {
if (gc_) { if (gc_) {
XFreeGC(display_, gc_); XFreeGC(display(), gc_);
gc_ = NULL; gc_ = NULL;
} }
x_server_pixel_buffer_.Release(); x_server_pixel_buffer_.Release();
if (display_) { if (display()) {
if (damage_handle_) if (damage_handle_) {
XDamageDestroy(display_, damage_handle_); XDamageDestroy(display(), damage_handle_);
if (damage_region_) damage_handle_ = 0;
XFixesDestroyRegion(display_, damage_region_); }
XCloseDisplay(display_);
display_ = NULL; if (damage_region_) {
damage_handle_ = 0; XFixesDestroyRegion(display(), damage_region_);
damage_region_ = 0; damage_region_ = 0;
}
} }
} }
} // namespace } // namespace
// static // static
ScreenCapturer* ScreenCapturer::Create() { ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); if (!options.x_display())
if (!capturer->Init(false)) return NULL;
capturer.reset();
return capturer.release();
}
// static
ScreenCapturer* ScreenCapturer::CreateWithXDamage(bool use_x_damage) {
scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux()); scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
if (!capturer->Init(use_x_damage)) if (!capturer->Init(options))
capturer.reset(); capturer.reset();
return capturer.release(); return capturer.release();
} }

View File

@ -0,0 +1,22 @@
/*
* 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 "webrtc/modules/desktop_capture/desktop_capture_options.h"
namespace webrtc {
// static
WindowCapturer* WindowCapturer::Create() {
return Create(DesktopCaptureOptions::CreateDefault());
}
} // namespace webrtc

View File

@ -20,6 +20,8 @@
namespace webrtc { namespace webrtc {
class DesktopCaptureOptions;
class WindowCapturer : public DesktopCapturer { class WindowCapturer : public DesktopCapturer {
public: public:
typedef intptr_t WindowId; typedef intptr_t WindowId;
@ -33,6 +35,9 @@ class WindowCapturer : public DesktopCapturer {
typedef std::vector<Window> WindowList; typedef std::vector<Window> WindowList;
static WindowCapturer* Create(const DesktopCaptureOptions& options);
// TODO(sergeyu): Remove this method. crbug.com/172183
static WindowCapturer* Create(); static WindowCapturer* Create();
virtual ~WindowCapturer() {} virtual ~WindowCapturer() {}

View File

@ -196,7 +196,7 @@ void WindowCapturerMac::Capture(const DesktopRegion& region) {
} // namespace } // namespace
// static // static
WindowCapturer* WindowCapturer::Create() { WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
return new WindowCapturerMac(); return new WindowCapturerMac();
} }

View File

@ -69,7 +69,7 @@ void WindowCapturerNull::Capture(const DesktopRegion& region) {
} // namespace } // namespace
// static // static
WindowCapturer* WindowCapturer::Create() { WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
return new WindowCapturerNull(); return new WindowCapturerNull();
} }

View File

@ -10,9 +10,8 @@
#include "webrtc/modules/desktop_capture/window_capturer.h" #include "webrtc/modules/desktop_capture/window_capturer.h"
#include <iostream>
#include "gtest/gtest.h" #include "gtest/gtest.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.h"
#include "webrtc/modules/desktop_capture/desktop_region.h" #include "webrtc/modules/desktop_capture/desktop_region.h"
#include "webrtc/system_wrappers/interface/logging.h" #include "webrtc/system_wrappers/interface/logging.h"
@ -24,7 +23,8 @@ class WindowCapturerTest : public testing::Test,
public DesktopCapturer::Callback { public DesktopCapturer::Callback {
public: public:
void SetUp() OVERRIDE { void SetUp() OVERRIDE {
capturer_.reset(WindowCapturer::Create()); capturer_.reset(
WindowCapturer::Create(DesktopCaptureOptions::CreateDefault()));
} }
void TearDown() OVERRIDE { void TearDown() OVERRIDE {

View File

@ -248,7 +248,7 @@ void WindowCapturerWin::Capture(const DesktopRegion& region) {
} // namespace } // namespace
// static // static
WindowCapturer* WindowCapturer::Create() { WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
return new WindowCapturerWin(); return new WindowCapturerWin();
} }

View File

@ -18,11 +18,14 @@
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h" #include "webrtc/modules/desktop_capture/desktop_frame.h"
#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
#include "webrtc/modules/desktop_capture/x11/x_error_trap.h" #include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h" #include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
#include "webrtc/system_wrappers/interface/logging.h" #include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
namespace webrtc { namespace webrtc {
@ -83,7 +86,7 @@ class XWindowProperty {
class WindowCapturerLinux : public WindowCapturer { class WindowCapturerLinux : public WindowCapturer {
public: public:
WindowCapturerLinux(); WindowCapturerLinux(const DesktopCaptureOptions& options);
virtual ~WindowCapturerLinux(); virtual ~WindowCapturerLinux();
// WindowCapturer interface. // WindowCapturer interface.
@ -95,6 +98,8 @@ class WindowCapturerLinux : public WindowCapturer {
virtual void Capture(const DesktopRegion& region) OVERRIDE; virtual void Capture(const DesktopRegion& region) OVERRIDE;
private: private:
Display* display() { return x_display_->display(); }
// Iterates through |window| hierarchy to find first visible window, i.e. one // Iterates through |window| hierarchy to find first visible window, i.e. one
// that has WM_STATE property set to NormalState. // that has WM_STATE property set to NormalState.
// See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 . // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 .
@ -108,7 +113,7 @@ class WindowCapturerLinux : public WindowCapturer {
Callback* callback_; Callback* callback_;
Display* display_; scoped_refptr<SharedXDisplay> x_display_;
Atom wm_state_atom_; Atom wm_state_atom_;
Atom window_type_atom_; Atom window_type_atom_;
@ -121,26 +126,20 @@ class WindowCapturerLinux : public WindowCapturer {
DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux); DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux);
}; };
WindowCapturerLinux::WindowCapturerLinux() WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options)
: callback_(NULL), : callback_(NULL),
display_(NULL), x_display_(options.x_display()),
has_composite_extension_(false), has_composite_extension_(false),
selected_window_(0) { selected_window_(0) {
display_ = XOpenDisplay(NULL);
if (!display_) {
LOG(LS_ERROR) << "Failed to open display.";
return;
}
// Create Atoms so we don't need to do it every time they are used. // Create Atoms so we don't need to do it every time they are used.
wm_state_atom_ = XInternAtom(display_, "WM_STATE", True); wm_state_atom_ = XInternAtom(display(), "WM_STATE", True);
window_type_atom_ = XInternAtom(display_, "_NET_WM_WINDOW_TYPE", True); window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True);
normal_window_type_atom_ = XInternAtom( normal_window_type_atom_ = XInternAtom(
display_, "_NET_WM_WINDOW_TYPE_NORMAL", True); display(), "_NET_WM_WINDOW_TYPE_NORMAL", True);
int event_base, error_base, major_version, minor_version; int event_base, error_base, major_version, minor_version;
if (XCompositeQueryExtension(display_, &event_base, &error_base) && if (XCompositeQueryExtension(display(), &event_base, &error_base) &&
XCompositeQueryVersion(display_, &major_version, &minor_version) && XCompositeQueryVersion(display(), &major_version, &minor_version) &&
// XCompositeNameWindowPixmap() requires version 0.2 // XCompositeNameWindowPixmap() requires version 0.2
(major_version > 0 || minor_version >= 2)) { (major_version > 0 || minor_version >= 2)) {
has_composite_extension_ = true; has_composite_extension_ = true;
@ -149,26 +148,20 @@ WindowCapturerLinux::WindowCapturerLinux()
} }
} }
WindowCapturerLinux::~WindowCapturerLinux() { WindowCapturerLinux::~WindowCapturerLinux() {}
if (display_)
XCloseDisplay(display_);
}
bool WindowCapturerLinux::GetWindowList(WindowList* windows) { bool WindowCapturerLinux::GetWindowList(WindowList* windows) {
if (!display_)
return false;
WindowList result; WindowList result;
XErrorTrap error_trap(display_); XErrorTrap error_trap(display());
int num_screens = XScreenCount(display_); int num_screens = XScreenCount(display());
for (int screen = 0; screen < num_screens; ++screen) { for (int screen = 0; screen < num_screens; ++screen) {
::Window root_window = XRootWindow(display_, screen); ::Window root_window = XRootWindow(display(), screen);
::Window parent; ::Window parent;
::Window *children; ::Window *children;
unsigned int num_children; unsigned int num_children;
int status = XQueryTree(display_, root_window, &root_window, &parent, int status = XQueryTree(display(), root_window, &root_window, &parent,
&children, &num_children); &children, &num_children);
if (status == 0) { if (status == 0) {
LOG(LS_ERROR) << "Failed to query for child windows for screen " LOG(LS_ERROR) << "Failed to query for child windows for screen "
@ -198,7 +191,7 @@ bool WindowCapturerLinux::GetWindowList(WindowList* windows) {
} }
bool WindowCapturerLinux::SelectWindow(WindowId id) { bool WindowCapturerLinux::SelectWindow(WindowId id) {
if (!x_server_pixel_buffer_.Init(display_, id)) if (!x_server_pixel_buffer_.Init(display(), id))
return false; return false;
selected_window_ = id; selected_window_ = id;
@ -210,7 +203,7 @@ bool WindowCapturerLinux::SelectWindow(WindowId id) {
// Redirect drawing to an offscreen buffer (ie, turn on compositing). X11 // Redirect drawing to an offscreen buffer (ie, turn on compositing). X11
// remembers who has requested this and will turn it off for us when we exit. // remembers who has requested this and will turn it off for us when we exit.
XCompositeRedirectWindow(display_, id, CompositeRedirectAutomatic); XCompositeRedirectWindow(display(), id, CompositeRedirectAutomatic);
return true; return true;
} }
@ -244,7 +237,7 @@ void WindowCapturerLinux::Capture(const DesktopRegion& region) {
::Window WindowCapturerLinux::GetApplicationWindow(::Window window) { ::Window WindowCapturerLinux::GetApplicationWindow(::Window window) {
// Get WM_STATE property of the window. // Get WM_STATE property of the window.
XWindowProperty<uint32_t> window_state(display_, window, wm_state_atom_); XWindowProperty<uint32_t> window_state(display(), window, wm_state_atom_);
// WM_STATE is considered to be set to WithdrawnState when it missing. // WM_STATE is considered to be set to WithdrawnState when it missing.
int32_t state = window_state.is_valid() ? int32_t state = window_state.is_valid() ?
@ -262,7 +255,7 @@ void WindowCapturerLinux::Capture(const DesktopRegion& region) {
::Window root, parent; ::Window root, parent;
::Window *children; ::Window *children;
unsigned int num_children; unsigned int num_children;
if (!XQueryTree(display_, window, &root, &parent, &children, if (!XQueryTree(display(), window, &root, &parent, &children,
&num_children)) { &num_children)) {
LOG(LS_ERROR) << "Failed to query for child windows although window" LOG(LS_ERROR) << "Failed to query for child windows although window"
<< "does not have a valid WM_STATE."; << "does not have a valid WM_STATE.";
@ -289,7 +282,7 @@ bool WindowCapturerLinux::IsDesktopElement(::Window window) {
// says this hint *should* be present on all windows, and we use the existence // says this hint *should* be present on all windows, and we use the existence
// of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not // of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not
// a desktop element (that is, only "normal" windows should be shareable). // a desktop element (that is, only "normal" windows should be shareable).
XWindowProperty<uint32_t> window_type(display_, window, window_type_atom_); XWindowProperty<uint32_t> window_type(display(), window, window_type_atom_);
if (window_type.is_valid() && window_type.size() > 0) { if (window_type.is_valid() && window_type.size() > 0) {
uint32_t* end = window_type.data() + window_type.size(); uint32_t* end = window_type.data() + window_type.size();
bool is_normal = (end != std::find( bool is_normal = (end != std::find(
@ -299,7 +292,7 @@ bool WindowCapturerLinux::IsDesktopElement(::Window window) {
// Fall back on using the hint. // Fall back on using the hint.
XClassHint class_hint; XClassHint class_hint;
Status status = XGetClassHint(display_, window, &class_hint); Status status = XGetClassHint(display(), window, &class_hint);
bool result = false; bool result = false;
if (status == 0) { if (status == 0) {
// No hints, assume this is a normal application window. // No hints, assume this is a normal application window.
@ -321,11 +314,11 @@ bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) {
XTextProperty window_name; XTextProperty window_name;
window_name.value = NULL; window_name.value = NULL;
if (window) { if (window) {
status = XGetWMName(display_, window, &window_name); status = XGetWMName(display(), window, &window_name);
if (status && window_name.value && window_name.nitems) { if (status && window_name.value && window_name.nitems) {
int cnt; int cnt;
char **list = NULL; char **list = NULL;
status = Xutf8TextPropertyToTextList(display_, &window_name, &list, status = Xutf8TextPropertyToTextList(display(), &window_name, &list,
&cnt); &cnt);
if (status >= Success && cnt && *list) { if (status >= Success && cnt && *list) {
if (cnt > 1) { if (cnt > 1) {
@ -347,8 +340,10 @@ bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) {
} // namespace } // namespace
// static // static
WindowCapturer* WindowCapturer::Create() { WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
return new WindowCapturerLinux(); if (!options.x_display())
return NULL;
return new WindowCapturerLinux(options);
} }
} // namespace webrtc } // namespace webrtc

View File

@ -0,0 +1,43 @@
/*
* 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/x11/shared_x_display.h"
#include "webrtc/system_wrappers/interface/logging.h"
namespace webrtc {
SharedXDisplay::SharedXDisplay(Display* display)
: display_(display) {
assert(display_);
}
SharedXDisplay::~SharedXDisplay() {
XCloseDisplay(display_);
}
// static
scoped_refptr<SharedXDisplay> SharedXDisplay::Create(
const std::string& display_name) {
Display* display =
XOpenDisplay(display_name.empty() ? NULL : display_name.c_str());
if (!display) {
LOG(LS_ERROR) << "Unable to open display";
return NULL;
}
return new SharedXDisplay(display);
}
// static
scoped_refptr<SharedXDisplay> SharedXDisplay::CreateDefault() {
return Create(std::string());
}
} // namespace webrtc

View File

@ -0,0 +1,58 @@
/*
* 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_X11_SHARED_X_DISPLAY_H_
#define WEBRTC_MODULES_DESKTOP_CAPTURE_X11_SHARED_X_DISPLAY_H_
#include <assert.h>
#include <X11/Xlib.h>
#include <string>
#include "webrtc/system_wrappers/interface/atomic32.h"
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
namespace webrtc {
// A ref-counted object to store XDisplay connection.
class SharedXDisplay {
public:
// Takes ownership of |display|.
explicit SharedXDisplay(Display* display);
void AddRef() { ++ref_count_; }
void Release() {
if (--ref_count_ == 0)
delete this;
}
Display* display() { return display_; }
// Creates a new X11 Display for the |display_name|. NULL is returned if X11
// connection failed. Equivalent to CreateDefault() when |display_name| is
// empty.
static scoped_refptr<SharedXDisplay> Create(const std::string& display_name);
// Creates X11 Display connection for the default display (e.g. specified in
// DISPLAY). NULL is returned if X11 connection failed.
static scoped_refptr<SharedXDisplay> CreateDefault();
private:
~SharedXDisplay();
Atomic32 ref_count_;
Display* display_;
DISALLOW_COPY_AND_ASSIGN(SharedXDisplay);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_X11_SHARED_X_DISPLAY_H_