diff --git a/webrtc/modules/desktop_capture/desktop_capture.gypi b/webrtc/modules/desktop_capture/desktop_capture.gypi index 0bc3839ef..50084c94f 100644 --- a/webrtc/modules/desktop_capture/desktop_capture.gypi +++ b/webrtc/modules/desktop_capture/desktop_capture.gypi @@ -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", diff --git a/webrtc/modules/desktop_capture/desktop_capture_options.cc b/webrtc/modules/desktop_capture/desktop_capture_options.cc new file mode 100644 index 000000000..a4fa02547 --- /dev/null +++ b/webrtc/modules/desktop_capture/desktop_capture_options.cc @@ -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 diff --git a/webrtc/modules/desktop_capture/desktop_capture_options.h b/webrtc/modules/desktop_capture/desktop_capture_options.h new file mode 100644 index 000000000..f0c76b173 --- /dev/null +++ b/webrtc/modules/desktop_capture/desktop_capture_options.h @@ -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 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 x_display_; +#endif + bool use_update_notifications_; + bool disable_effects_; +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_DESKTOP_CAPTURE_OPTIONS_H_ diff --git a/webrtc/modules/desktop_capture/screen_capturer.cc b/webrtc/modules/desktop_capture/screen_capturer.cc new file mode 100644 index 000000000..97f69d3ba --- /dev/null +++ b/webrtc/modules/desktop_capture/screen_capturer.cc @@ -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 diff --git a/webrtc/modules/desktop_capture/screen_capturer.h b/webrtc/modules/desktop_capture/screen_capturer.h index 17101c522..9dd3a1050 100644 --- a/webrtc/modules/desktop_capture/screen_capturer.h +++ b/webrtc/modules/desktop_capture/screen_capturer.h @@ -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) diff --git a/webrtc/modules/desktop_capture/screen_capturer_mac.mm b/webrtc/modules/desktop_capture/screen_capturer_mac.mm index 3165fd3aa..5cbffb06f 100644 --- a/webrtc/modules/desktop_capture/screen_capturer_mac.mm +++ b/webrtc/modules/desktop_capture/screen_capturer_mac.mm @@ -21,6 +21,7 @@ #include #include +#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 capturer(new ScreenCapturerMac()); if (!capturer->Init()) capturer.reset(); diff --git a/webrtc/modules/desktop_capture/screen_capturer_null.cc b/webrtc/modules/desktop_capture/screen_capturer_null.cc index a94d6035e..a0bc7f13e 100644 --- a/webrtc/modules/desktop_capture/screen_capturer_null.cc +++ b/webrtc/modules/desktop_capture/screen_capturer_null.cc @@ -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 diff --git a/webrtc/modules/desktop_capture/screen_capturer_unittest.cc b/webrtc/modules/desktop_capture/screen_capturer_unittest.cc index d5ba213ef..b4ae12808 100644 --- a/webrtc/modules/desktop_capture/screen_capturer_unittest.cc +++ b/webrtc/modules/desktop_capture/screen_capturer_unittest.cc @@ -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 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(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()); diff --git a/webrtc/modules/desktop_capture/screen_capturer_win.cc b/webrtc/modules/desktop_capture/screen_capturer_win.cc index 969b6a5a4..af9b18b0a 100644 --- a/webrtc/modules/desktop_capture/screen_capturer_win.cc +++ b/webrtc/modules/desktop_capture/screen_capturer_win.cc @@ -12,6 +12,7 @@ #include +#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 diff --git a/webrtc/modules/desktop_capture/screen_capturer_x11.cc b/webrtc/modules/desktop_capture/screen_capturer_x11.cc index 5cca65b13..780d8cf6d 100644 --- a/webrtc/modules/desktop_capture/screen_capturer_x11.cc +++ b/webrtc/modules/desktop_capture/screen_capturer_x11.cc @@ -18,6 +18,7 @@ #include #include +#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(&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; - damage_handle_ = 0; - damage_region_ = 0; + 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 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 capturer(new ScreenCapturerLinux()); - if (!capturer->Init(use_x_damage)) + if (!capturer->Init(options)) capturer.reset(); return capturer.release(); } diff --git a/webrtc/modules/desktop_capture/window_capturer.cc b/webrtc/modules/desktop_capture/window_capturer.cc new file mode 100644 index 000000000..c5176d5e6 --- /dev/null +++ b/webrtc/modules/desktop_capture/window_capturer.cc @@ -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 diff --git a/webrtc/modules/desktop_capture/window_capturer.h b/webrtc/modules/desktop_capture/window_capturer.h index 8cc57c14d..4e25c1ba0 100644 --- a/webrtc/modules/desktop_capture/window_capturer.h +++ b/webrtc/modules/desktop_capture/window_capturer.h @@ -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 WindowList; + static WindowCapturer* Create(const DesktopCaptureOptions& options); + + // TODO(sergeyu): Remove this method. crbug.com/172183 static WindowCapturer* Create(); virtual ~WindowCapturer() {} diff --git a/webrtc/modules/desktop_capture/window_capturer_mac.cc b/webrtc/modules/desktop_capture/window_capturer_mac.cc index e78d95bc2..78f618d26 100755 --- a/webrtc/modules/desktop_capture/window_capturer_mac.cc +++ b/webrtc/modules/desktop_capture/window_capturer_mac.cc @@ -196,7 +196,7 @@ void WindowCapturerMac::Capture(const DesktopRegion& region) { } // namespace // static -WindowCapturer* WindowCapturer::Create() { +WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { return new WindowCapturerMac(); } diff --git a/webrtc/modules/desktop_capture/window_capturer_null.cc b/webrtc/modules/desktop_capture/window_capturer_null.cc index 8ea723aaa..7bb1247ea 100755 --- a/webrtc/modules/desktop_capture/window_capturer_null.cc +++ b/webrtc/modules/desktop_capture/window_capturer_null.cc @@ -69,7 +69,7 @@ void WindowCapturerNull::Capture(const DesktopRegion& region) { } // namespace // static -WindowCapturer* WindowCapturer::Create() { +WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { return new WindowCapturerNull(); } diff --git a/webrtc/modules/desktop_capture/window_capturer_unittest.cc b/webrtc/modules/desktop_capture/window_capturer_unittest.cc index c6de16ac4..ad60a4bd1 100644 --- a/webrtc/modules/desktop_capture/window_capturer_unittest.cc +++ b/webrtc/modules/desktop_capture/window_capturer_unittest.cc @@ -10,9 +10,8 @@ #include "webrtc/modules/desktop_capture/window_capturer.h" -#include - #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 { diff --git a/webrtc/modules/desktop_capture/window_capturer_win.cc b/webrtc/modules/desktop_capture/window_capturer_win.cc index 8fd380b37..95f41db73 100644 --- a/webrtc/modules/desktop_capture/window_capturer_win.cc +++ b/webrtc/modules/desktop_capture/window_capturer_win.cc @@ -248,7 +248,7 @@ void WindowCapturerWin::Capture(const DesktopRegion& region) { } // namespace // static -WindowCapturer* WindowCapturer::Create() { +WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { return new WindowCapturerWin(); } diff --git a/webrtc/modules/desktop_capture/window_capturer_x11.cc b/webrtc/modules/desktop_capture/window_capturer_x11.cc index adafa9450..5a14356fd 100755 --- a/webrtc/modules/desktop_capture/window_capturer_x11.cc +++ b/webrtc/modules/desktop_capture/window_capturer_x11.cc @@ -18,11 +18,14 @@ #include #include +#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 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 window_state(display_, window, wm_state_atom_); + XWindowProperty 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 window_type(display_, window, window_type_atom_); + XWindowProperty 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 diff --git a/webrtc/modules/desktop_capture/x11/shared_x_display.cc b/webrtc/modules/desktop_capture/x11/shared_x_display.cc new file mode 100644 index 000000000..c8f5a3796 --- /dev/null +++ b/webrtc/modules/desktop_capture/x11/shared_x_display.cc @@ -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::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::CreateDefault() { + return Create(std::string()); +} + +} // namespace webrtc diff --git a/webrtc/modules/desktop_capture/x11/shared_x_display.h b/webrtc/modules/desktop_capture/x11/shared_x_display.h new file mode 100644 index 000000000..93f686702 --- /dev/null +++ b/webrtc/modules/desktop_capture/x11/shared_x_display.h @@ -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 +#include + +#include + +#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 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 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_