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_geometry.cc",
"desktop_geometry.h",
"desktop_capture_options.h",
"desktop_capture_options.cc",
"desktop_capturer.h",
"desktop_region.cc",
"desktop_region.h",
"differ.cc",
@ -35,6 +38,7 @@
"mouse_cursor_shape.h",
"screen_capture_frame_queue.cc",
"screen_capture_frame_queue.h",
"screen_capturer.cc",
"screen_capturer.h",
"screen_capturer_helper.cc",
"screen_capturer_helper.h",
@ -52,10 +56,13 @@
"win/scoped_gdi_object.h",
"win/scoped_thread_desktop.cc",
"win/scoped_thread_desktop.h",
"window_capturer.cc",
"window_capturer.h",
"window_capturer_mac.cc",
"window_capturer_win.cc",
"window_capturer_x11.cc",
"x11/shared_x_display.h",
"x11/shared_x_display.cc",
"x11/x_error_trap.cc",
"x11/x_error_trap.h",
"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 {
class DesktopCaptureOptions;
struct MouseCursorShape;
// Class used to capture video frames asynchronously.
@ -57,6 +58,10 @@ class ScreenCapturer : public DesktopCapturer {
virtual ~ScreenCapturer() {}
// 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();
#if defined(WEBRTC_LINUX)

View File

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

View File

@ -13,20 +13,8 @@
namespace webrtc {
// static
ScreenCapturer* ScreenCapturer::Create() {
ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,11 +18,14 @@
#include <algorithm>
#include <cassert>
#include "webrtc/modules/desktop_capture/desktop_capture_options.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_server_pixel_buffer.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
namespace webrtc {
@ -83,7 +86,7 @@ class XWindowProperty {
class WindowCapturerLinux : public WindowCapturer {
public:
WindowCapturerLinux();
WindowCapturerLinux(const DesktopCaptureOptions& options);
virtual ~WindowCapturerLinux();
// WindowCapturer interface.
@ -95,6 +98,8 @@ class WindowCapturerLinux : public WindowCapturer {
virtual void Capture(const DesktopRegion& region) OVERRIDE;
private:
Display* display() { return x_display_->display(); }
// Iterates through |window| hierarchy to find first visible window, i.e. one
// that has WM_STATE property set to NormalState.
// 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_;
Display* display_;
scoped_refptr<SharedXDisplay> x_display_;
Atom wm_state_atom_;
Atom window_type_atom_;
@ -121,26 +126,20 @@ class WindowCapturerLinux : public WindowCapturer {
DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux);
};
WindowCapturerLinux::WindowCapturerLinux()
WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options)
: callback_(NULL),
display_(NULL),
x_display_(options.x_display()),
has_composite_extension_(false),
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.
wm_state_atom_ = XInternAtom(display_, "WM_STATE", True);
window_type_atom_ = XInternAtom(display_, "_NET_WM_WINDOW_TYPE", True);
wm_state_atom_ = XInternAtom(display(), "WM_STATE", True);
window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True);
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;
if (XCompositeQueryExtension(display_, &event_base, &error_base) &&
XCompositeQueryVersion(display_, &major_version, &minor_version) &&
if (XCompositeQueryExtension(display(), &event_base, &error_base) &&
XCompositeQueryVersion(display(), &major_version, &minor_version) &&
// XCompositeNameWindowPixmap() requires version 0.2
(major_version > 0 || minor_version >= 2)) {
has_composite_extension_ = true;
@ -149,26 +148,20 @@ WindowCapturerLinux::WindowCapturerLinux()
}
}
WindowCapturerLinux::~WindowCapturerLinux() {
if (display_)
XCloseDisplay(display_);
}
WindowCapturerLinux::~WindowCapturerLinux() {}
bool WindowCapturerLinux::GetWindowList(WindowList* windows) {
if (!display_)
return false;
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) {
::Window root_window = XRootWindow(display_, screen);
::Window root_window = XRootWindow(display(), screen);
::Window parent;
::Window *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);
if (status == 0) {
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) {
if (!x_server_pixel_buffer_.Init(display_, id))
if (!x_server_pixel_buffer_.Init(display(), id))
return false;
selected_window_ = id;
@ -210,7 +203,7 @@ bool WindowCapturerLinux::SelectWindow(WindowId id) {
// 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.
XCompositeRedirectWindow(display_, id, CompositeRedirectAutomatic);
XCompositeRedirectWindow(display(), id, CompositeRedirectAutomatic);
return true;
}
@ -244,7 +237,7 @@ void WindowCapturerLinux::Capture(const DesktopRegion& region) {
::Window WindowCapturerLinux::GetApplicationWindow(::Window 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.
int32_t state = window_state.is_valid() ?
@ -262,7 +255,7 @@ void WindowCapturerLinux::Capture(const DesktopRegion& region) {
::Window root, parent;
::Window *children;
unsigned int num_children;
if (!XQueryTree(display_, window, &root, &parent, &children,
if (!XQueryTree(display(), window, &root, &parent, &children,
&num_children)) {
LOG(LS_ERROR) << "Failed to query for child windows although window"
<< "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
// 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).
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) {
uint32_t* end = window_type.data() + window_type.size();
bool is_normal = (end != std::find(
@ -299,7 +292,7 @@ bool WindowCapturerLinux::IsDesktopElement(::Window window) {
// Fall back on using the hint.
XClassHint class_hint;
Status status = XGetClassHint(display_, window, &class_hint);
Status status = XGetClassHint(display(), window, &class_hint);
bool result = false;
if (status == 0) {
// No hints, assume this is a normal application window.
@ -321,11 +314,11 @@ bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) {
XTextProperty window_name;
window_name.value = NULL;
if (window) {
status = XGetWMName(display_, window, &window_name);
status = XGetWMName(display(), window, &window_name);
if (status && window_name.value && window_name.nitems) {
int cnt;
char **list = NULL;
status = Xutf8TextPropertyToTextList(display_, &window_name, &list,
status = Xutf8TextPropertyToTextList(display(), &window_name, &list,
&cnt);
if (status >= Success && cnt && *list) {
if (cnt > 1) {
@ -347,8 +340,10 @@ bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) {
} // namespace
// static
WindowCapturer* WindowCapturer::Create() {
return new WindowCapturerLinux();
WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
if (!options.x_display())
return NULL;
return new WindowCapturerLinux(options);
}
} // 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_