Bug 1307254: Implement ::Stop() for screen/window/app capture r=jib
authorRandell Jesup <rjesup@jesup.org>
Wed, 05 Oct 2016 16:15:19 -0400
changeset 316714 15d8cf76620f038959557d6c03ead97ba050b2ff
parent 316713 4bc3a6811a690b862b646482de2001c21a98aeaa
child 316715 84df59f2684ef80021b86f634d8b4adcfab86c96
push id30780
push usercbook@mozilla.com
push dateThu, 06 Oct 2016 10:00:07 +0000
treeherdermozilla-central@777fb63db8de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib
bugs1307254
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1307254: Implement ::Stop() for screen/window/app capture r=jib
media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_mac.mm
media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_null.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_win.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/cropping_window_capturer.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/cropping_window_capturer.h
media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.h
media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h
media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor.h
media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_unittest.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_mac.mm
media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h
media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h
media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm
media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_null.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc
media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc
media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.h
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_mac.mm
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_mac.mm
@@ -32,16 +32,17 @@ class AppCapturerMac : public AppCapture
 
   // AppCapturer interface.
   virtual bool GetAppList(AppList* apps) override;
   virtual bool SelectApp(ProcessId processId) override;
   virtual bool BringAppToFront() override;
 
   // DesktopCapturer interface.
   virtual void Start(Callback* callback) override;
+  virtual void Stop() override;
   virtual void Capture(const DesktopRegion& region) override;
 
  private:
   Callback* callback_;
   ProcessId process_id_;
 
   DISALLOW_COPY_AND_ASSIGN(AppCapturerMac);
 };
@@ -73,16 +74,20 @@ bool AppCapturerMac::BringAppToFront() {
 // DesktopCapturer interface.
 void AppCapturerMac::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
 
+void AppCapturerMac::Stop() {
+  callback_ = NULL;
+}
+
 void AppCapturerMac::Capture(const DesktopRegion& region) {
   // Check that selected process exists
   NSRunningApplication *ra = [NSRunningApplication runningApplicationWithProcessIdentifier:process_id_];
   if (!ra) {
     callback_->OnCaptureCompleted(NULL);
     return;
   }
 
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_null.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_null.cc
@@ -25,16 +25,17 @@ public:
 
   // AppCapturer interface.
   virtual bool GetAppList(AppList* apps) override;
   virtual bool SelectApp(ProcessId id) override;
   virtual bool BringAppToFront()	override;
 
   // DesktopCapturer interface.
   virtual void Start(Callback* callback) override;
+  virtual void Stop() override;
   virtual void Capture(const DesktopRegion& region) override;
 
 private:
   Callback* callback_;
 
   DISALLOW_COPY_AND_ASSIGN(AppCapturerNull);
 };
 
@@ -63,16 +64,20 @@ bool AppCapturerNull::BringAppToFront() 
 // DesktopCapturer interface.
 void AppCapturerNull::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
 
+void AppCapturerNull::Stop() {
+  callback_ = NULL;
+}
+
 void AppCapturerNull::Capture(const DesktopRegion& region) {
   // Not implemented yet: See Bug 1036653
   callback_->OnCaptureCompleted(NULL);
 }
 
 }  // namespace
 
 // static
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_win.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_win.cc
@@ -75,16 +75,17 @@ public:
 
   // AppCapturer interface.
   virtual bool GetAppList(AppList* apps) override;
   virtual bool SelectApp(ProcessId processId) override;
   virtual bool BringAppToFront() override;
 
   // DesktopCapturer interface.
   virtual void Start(Callback* callback) override;
+  virtual void Stop() override;
   virtual void Capture(const DesktopRegion& region) override;
 
   struct WindowItem {
     HWND handle;
     RECT bounds;
     bool owned;
   };
 
@@ -160,16 +161,19 @@ bool AppCapturerWin::BringAppToFront() {
 
 // DesktopCapturer interface.
 void AppCapturerWin::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
+void AppCapturerWin::Stop() {
+  callback_ = NULL;
+}
 void AppCapturerWin::Capture(const DesktopRegion& region) {
   assert(IsGUIThread(false));
   CaptureBySample(region);
 }
 
 BOOL CALLBACK AppCapturerWin::EnumWindowsProc(HWND handle, LPARAM lParam) {
   EnumWindowsCtx *pEnumWindowsCtx = reinterpret_cast<EnumWindowsCtx *>(lParam);
   if (!pEnumWindowsCtx) {
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc
@@ -79,16 +79,17 @@ public:
 
   // AppCapturer interface.
   virtual bool GetAppList(AppList* apps) override;
   virtual bool SelectApp(ProcessId processId) override;
   virtual bool BringAppToFront() override;
 
   // DesktopCapturer interface.
   virtual void Start(Callback* callback) override;
+  virtual void Stop() override;
   virtual void Capture(const DesktopRegion& region) override;
 
 protected:
   Display* GetDisplay() { return x_display_->display(); }
   bool UpdateRegions();
 
   void CaptureWebRTC(const DesktopRegion& region);
   void CaptureSample(const DesktopRegion& region);
@@ -152,16 +153,20 @@ bool AppCapturerLinux::BringAppToFront()
 // DesktopCapturer interface.
 void AppCapturerLinux::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
 
+void AppCapturerLinux::Stop() {
+  callback_ = NULL;
+}
+
 void AppCapturerLinux::Capture(const DesktopRegion& region) {
   CaptureSample(region);
 }
 
 void AppCapturerLinux::CaptureWebRTC(const DesktopRegion& region) {
   XErrorTrap error_trap(GetDisplay());
 
   int nScreenWidth = DisplayWidth(GetDisplay(), DefaultScreen(GetDisplay()));
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/cropping_window_capturer.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/cropping_window_capturer.cc
@@ -26,16 +26,21 @@ CroppingWindowCapturer::CroppingWindowCa
 
 CroppingWindowCapturer::~CroppingWindowCapturer() {}
 
 void CroppingWindowCapturer::Start(DesktopCapturer::Callback* callback) {
   callback_ = callback;
   window_capturer_->Start(callback);
 }
 
+void CroppingWindowCapturer::Stop() {
+  window_capturer_->Stop();
+  callback_ = NULL;
+}
+
 void CroppingWindowCapturer::Capture(const DesktopRegion& region) {
   if (ShouldUseScreenCapturer()) {
     if (!screen_capturer_.get()) {
       screen_capturer_.reset(ScreenCapturer::Create(options_));
       if (excluded_window_) {
         screen_capturer_->SetExcludedWindow(excluded_window_);
       }
       screen_capturer_->Start(this);
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/cropping_window_capturer.h
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/cropping_window_capturer.h
@@ -24,16 +24,17 @@ namespace webrtc {
 class CroppingWindowCapturer : public WindowCapturer,
                                public DesktopCapturer::Callback {
  public:
   static WindowCapturer* Create(const DesktopCaptureOptions& options);
   virtual ~CroppingWindowCapturer();
 
   // DesktopCapturer implementation.
   void Start(DesktopCapturer::Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
   void SetExcludedWindow(WindowId window) override;
 
   // WindowCapturer implementation.
   bool GetWindowList(WindowList* windows) override;
   bool SelectWindow(WindowId id) override;
   bool BringSelectedWindowToFront() override;
 
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.cc
@@ -127,20 +127,27 @@ DesktopAndCursorComposer::DesktopAndCurs
       mouse_monitor_(mouse_monitor) {
 }
 
 DesktopAndCursorComposer::~DesktopAndCursorComposer() {}
 
 void DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) {
   callback_ = callback;
   if (mouse_monitor_.get())
-    mouse_monitor_->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION);
+    mouse_monitor_->Start(this, MouseCursorMonitor::SHAPE_AND_POSITION);
   desktop_capturer_->Start(this);
 }
 
+void DesktopAndCursorComposer::Stop() {
+  desktop_capturer_->Stop();
+  if (mouse_monitor_.get())
+    mouse_monitor_->Stop();
+  callback_ = NULL;
+}
+
 void DesktopAndCursorComposer::Capture(const DesktopRegion& region) {
   if (mouse_monitor_.get())
     mouse_monitor_->Capture();
   desktop_capturer_->Capture(region);
 }
 
 void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) {
   desktop_capturer_->SetExcludedWindow(window);
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.h
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.h
@@ -28,16 +28,17 @@ class DesktopAndCursorComposer : public 
   // |mouse_monitor| is NULL the frames are passed unmodified. Takes ownership
   // of both arguments.
   DesktopAndCursorComposer(DesktopCapturer* desktop_capturer,
                       MouseCursorMonitor* mouse_monitor);
   virtual ~DesktopAndCursorComposer();
 
   // DesktopCapturer interface.
   void Start(DesktopCapturer::Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
   void SetExcludedWindow(WindowId window) override;
 
  private:
   // DesktopCapturer::Callback interface.
   SharedMemory* CreateSharedMemory(size_t size) override;
   void OnCaptureCompleted(DesktopFrame* frame) override;
 
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h
@@ -39,18 +39,19 @@ class DesktopCapturer {
 
    protected:
     virtual ~Callback() {}
   };
 
   virtual ~DesktopCapturer() {}
 
   // Called at the beginning of a capturing session. |callback| must remain
-  // valid until capturer is destroyed.
+  // valid until capturer is destroyed or until Stop() is called
   virtual void Start(Callback* callback) = 0;
+  virtual void Stop() = 0;
 
   // Captures next frame. |region| specifies region of the capture target that
   // should be fresh in the resulting frame. The frame may also include fresh
   // data for areas outside |region|. In that case capturer will include these
   // areas in updated_region() of the frame. |region| is specified relative to
   // the top left corner of the capture target. Pending capture operations are
   // canceled when DesktopCapturer is deleted.
   virtual void Capture(const DesktopRegion& region) = 0;
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor.h
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor.h
@@ -68,18 +68,21 @@ class MouseCursorMonitor {
   // the entire desktop.
   //
   // TODO(sergeyu): Provide a way to select a specific screen.
   static MouseCursorMonitor* CreateForScreen(
       const DesktopCaptureOptions& options,
       ScreenId screen);
 
   // Initializes the monitor with the |callback|, which must remain valid until
-  // capturer is destroyed.
-  virtual void Init(Callback* callback, Mode mode) = 0;
+  // capturer is destroyed or until Stop()
+  virtual void Start(Callback* callback, Mode mode) = 0;
+
+  // clears the callback
+  virtual void Stop() = 0;
 
   // Captures current cursor shape and position (depending on the |mode| passed
   // to Init()). Calls Callback::OnMouseCursor() if cursor shape has
   // changed since the last call (or when Capture() is called for the first
   // time) and then Callback::OnMouseCursorPosition() if mode is set to
   // SHAPE_AND_POSITION.
   virtual void Capture() = 0;
 };
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
@@ -30,17 +30,18 @@ namespace webrtc {
 
 class MouseCursorMonitorMac : public MouseCursorMonitor {
  public:
   MouseCursorMonitorMac(const DesktopCaptureOptions& options,
                         CGWindowID window_id,
                         ScreenId screen_id);
   virtual ~MouseCursorMonitorMac();
 
-  void Init(Callback* callback, Mode mode) override;
+  void Start(Callback* callback, Mode mode) override;
+  void Stop() override;
   void Capture() override;
 
  private:
   static void DisplaysReconfiguredCallback(CGDirectDisplayID display,
                                            CGDisplayChangeSummaryFlags flags,
                                            void *user_parameter);
   void DisplaysReconfigured(CGDirectDisplayID display,
                             CGDisplayChangeSummaryFlags flags);
@@ -73,24 +74,28 @@ MouseCursorMonitorMac::MouseCursorMonito
       rtc::GetOSVersionName() < rtc::kMacOSLion) {
     // Single screen capture is not supported on pre OS X 10.7.
     screen_id_ = kFullDesktopScreenId;
   }
 }
 
 MouseCursorMonitorMac::~MouseCursorMonitorMac() {}
 
-void MouseCursorMonitorMac::Init(Callback* callback, Mode mode) {
+void MouseCursorMonitorMac::Start(Callback* callback, Mode mode) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
   mode_ = mode;
 }
 
+void MouseCursorMonitorMac::Stop() {
+  callback_ = NULL;
+}
+
 void MouseCursorMonitorMac::Capture() {
   assert(callback_);
 
   CaptureImage();
 
   if (mode_ != SHAPE_AND_POSITION)
     return;
 
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_unittest.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_unittest.cc
@@ -62,17 +62,17 @@ class MouseCursorMonitorTest : public te
 #endif
 
 TEST_F(MouseCursorMonitorTest, MAYBE(FromScreen)) {
   rtc::scoped_ptr<MouseCursorMonitor> capturer(
       MouseCursorMonitor::CreateForScreen(
           DesktopCaptureOptions::CreateDefault(),
           webrtc::kFullDesktopScreenId));
   assert(capturer.get());
-  capturer->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION);
+  capturer->Start(this, MouseCursorMonitor::SHAPE_AND_POSITION);
   capturer->Capture();
 
   EXPECT_TRUE(cursor_image_.get());
   EXPECT_GE(cursor_image_->hotspot().x(), 0);
   EXPECT_LE(cursor_image_->hotspot().x(),
             cursor_image_->image()->size().width());
   EXPECT_GE(cursor_image_->hotspot().y(), 0);
   EXPECT_LE(cursor_image_->hotspot().y(),
@@ -101,31 +101,31 @@ TEST_F(MouseCursorMonitorTest, MAYBE(Fro
     cursor_image_.reset();
     position_received_ = false;
 
     rtc::scoped_ptr<MouseCursorMonitor> capturer(
         MouseCursorMonitor::CreateForWindow(
             DesktopCaptureOptions::CreateDefault(), windows[i].id));
     assert(capturer.get());
 
-    capturer->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION);
+    capturer->Start(this, MouseCursorMonitor::SHAPE_AND_POSITION);
     capturer->Capture();
 
     EXPECT_TRUE(cursor_image_.get());
     EXPECT_TRUE(position_received_);
   }
 }
 
 // Make sure that OnMouseCursorPosition() is not called in the SHAPE_ONLY mode.
 TEST_F(MouseCursorMonitorTest, MAYBE(ShapeOnly)) {
   rtc::scoped_ptr<MouseCursorMonitor> capturer(
       MouseCursorMonitor::CreateForScreen(
           DesktopCaptureOptions::CreateDefault(),
           webrtc::kFullDesktopScreenId));
   assert(capturer.get());
-  capturer->Init(this, MouseCursorMonitor::SHAPE_ONLY);
+  capturer->Start(this, MouseCursorMonitor::SHAPE_ONLY);
   capturer->Capture();
 
   EXPECT_TRUE(cursor_image_.get());
   EXPECT_FALSE(position_received_);
 }
 
 }  // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_win.cc
@@ -21,17 +21,18 @@
 namespace webrtc {
 
 class MouseCursorMonitorWin : public MouseCursorMonitor {
  public:
   explicit MouseCursorMonitorWin(HWND window);
   explicit MouseCursorMonitorWin(ScreenId screen);
   virtual ~MouseCursorMonitorWin();
 
-  void Init(Callback* callback, Mode mode) override;
+  void Start(Callback* callback, Mode mode) override;
+  void Stop() override;
   void Capture() override;
 
  private:
   // Get the rect of the currently selected screen, relative to the primary
   // display's top-left. If the screen is disabled or disconnected, or any error
   // happens, an empty rect is returned.
   DesktopRect GetScreenRect();
 
@@ -65,27 +66,35 @@ MouseCursorMonitorWin::MouseCursorMonito
   assert(screen >= kFullDesktopScreenId);
 }
 
 MouseCursorMonitorWin::~MouseCursorMonitorWin() {
   if (desktop_dc_)
     ReleaseDC(NULL, desktop_dc_);
 }
 
-void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) {
+void MouseCursorMonitorWin::Start(Callback* callback, Mode mode) {
   assert(!callback_);
   assert(callback);
   assert(IsGUIThread(false));
 
   callback_ = callback;
   mode_ = mode;
 
   desktop_dc_ = GetDC(NULL);
 }
 
+void MouseCursorMonitorWin::Stop() {
+  callback_ = NULL;
+
+  if (desktop_dc_)
+    ReleaseDC(NULL, desktop_dc_);
+  desktop_dc_ = NULL;
+}
+
 void MouseCursorMonitorWin::Capture() {
   assert(IsGUIThread(false));
   assert(callback_);
 
   CURSORINFO cursor_info;
   cursor_info.cbSize = sizeof(CURSORINFO);
   if (!GetCursorInfo(&cursor_info)) {
     LOG_F(LS_ERROR) << "Unable to get cursor info. Error = " << GetLastError();
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc
@@ -59,17 +59,18 @@ Window GetTopLevelWindow(Display* displa
 namespace webrtc {
 
 class MouseCursorMonitorX11 : public MouseCursorMonitor,
                               public SharedXDisplay::XEventHandler {
  public:
   MouseCursorMonitorX11(const DesktopCaptureOptions& options, Window window, Window inner_window);
   virtual ~MouseCursorMonitorX11();
 
-  void Init(Callback* callback, Mode mode) override;
+  void Start(Callback* callback, Mode mode) override;
+  void Stop() override;
   void Capture() override;
 
  private:
   // SharedXDisplay::XEventHandler interface.
   bool HandleXEvent(const XEvent& event) override;
 
   Display* display() { return x_display_->display(); }
 
@@ -98,24 +99,21 @@ MouseCursorMonitorX11::MouseCursorMonito
       mode_(SHAPE_AND_POSITION),
       window_(window),
       inner_window_(inner_window),
       have_xfixes_(false),
       xfixes_event_base_(-1),
       xfixes_error_base_(-1) {}
 
 MouseCursorMonitorX11::~MouseCursorMonitorX11() {
-  if (have_xfixes_) {
-    x_display_->RemoveEventHandler(xfixes_event_base_ + XFixesCursorNotify,
-                                   this);
-  }
+  Stop();
 }
 
-void MouseCursorMonitorX11::Init(Callback* callback, Mode mode) {
-  // Init can be called only once per instance of MouseCursorMonitor.
+void MouseCursorMonitorX11::Start(Callback* callback, Mode mode) {
+  // Start can be called only if not started
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
   mode_ = mode;
 
   have_xfixes_ =
       XFixesQueryExtension(display(), &xfixes_event_base_, &xfixes_error_base_);
@@ -127,16 +125,24 @@ void MouseCursorMonitorX11::Init(Callbac
     x_display_->AddEventHandler(xfixes_event_base_ + XFixesCursorNotify, this);
 
     CaptureCursor();
   } else {
     LOG(LS_INFO) << "X server does not support XFixes.";
   }
 }
 
+void MouseCursorMonitorX11::Stop() {
+  callback_ = NULL;
+  if (have_xfixes_) {
+    x_display_->RemoveEventHandler(xfixes_event_base_ + XFixesCursorNotify,
+                                   this);
+  }
+}
+
 void MouseCursorMonitorX11::Capture() {
   assert(callback_);
 
   // Process X11 events in case XFixes has sent cursor notification.
   x_display_->ProcessPendingXEvents();
 
   // cursor_shape_| is set only if we were notified of a cursor shape change.
   if (cursor_shape_.get())
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_mac.mm
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_mac.mm
@@ -192,16 +192,17 @@ class ScreenCapturerMac : public ScreenC
   explicit ScreenCapturerMac(
       scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor);
   virtual ~ScreenCapturerMac();
 
   bool Init();
 
   // Overridden from ScreenCapturer:
   void Start(Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
   void SetExcludedWindow(WindowId window) override;
   bool GetScreenList(ScreenList* screens) override;
   bool SelectScreen(ScreenId id) override;
 
  private:
   void GlBlitFast(const DesktopFrame& frame,
                   const DesktopRegion& region);
@@ -380,16 +381,29 @@ void ScreenCapturerMac::Start(Callback* 
   // This assertion ensures that the display is woken up if it  already asleep
   // (as used by Apple Remote Desktop).
   IOPMAssertionCreateWithName(CFSTR("UserIsActive"),
                               kIOPMAssertionLevelOn,
                               CFSTR("Chrome Remote Desktop connection active"),
                               &power_assertion_id_user_);
 }
 
+void ScreenCapturerMac::Stop() {
+  if (power_assertion_id_display_ != kIOPMNullAssertionID) {
+    IOPMAssertionRelease(power_assertion_id_display_);
+    power_assertion_id_display_ = kIOPMNullAssertionID;
+  }
+  if (power_assertion_id_user_ != kIOPMNullAssertionID) {
+    IOPMAssertionRelease(power_assertion_id_user_);
+    power_assertion_id_user_ = kIOPMNullAssertionID;
+  }
+
+  callback_ = NULL;
+}
+
 void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) {
   TickTime capture_start_time = TickTime::Now();
 
   queue_.MoveToNextFrame();
 
   desktop_config_monitor_->Lock();
   MacDesktopConfiguration new_config =
       desktop_config_monitor_->desktop_configuration();
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.cc
@@ -46,16 +46,17 @@ class ScreenCapturerLinux : public Scree
   ScreenCapturerLinux();
   virtual ~ScreenCapturerLinux();
 
   // TODO(ajwong): Do we really want this to be synchronous?
   bool Init(const DesktopCaptureOptions& options);
 
   // DesktopCapturer interface.
   void Start(Callback* delegate) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
 
   // ScreenCapturer interface.
   bool GetScreenList(ScreenList* screens) override;
   bool SelectScreen(ScreenId id) override;
 
  private:
   Display* display() { return options_.x_display()->display(); }
@@ -234,16 +235,20 @@ void ScreenCapturerLinux::InitXDamage() 
 
 void ScreenCapturerLinux::Start(Callback* callback) {
   DCHECK(!callback_);
   DCHECK(callback);
 
   callback_ = callback;
 }
 
+void ScreenCapturerLinux::Stop() {
+  callback_ = NULL;
+}
+
 void ScreenCapturerLinux::Capture(const DesktopRegion& region) {
   TickTime capture_start_time = TickTime::Now();
 
   queue_.MoveToNextFrame();
 
   // Process XEvents for XDamage and cursor shape tracking.
   options_.x_display()->ProcessPendingXEvents();
 
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc
@@ -54,26 +54,17 @@ ScreenCapturerWinGdi::ScreenCapturerWinG
     composition_enabled_func_ = reinterpret_cast<DwmIsCompositionEnabledFunc>
       (GetProcAddress(dwmapi_library_, "DwmIsCompositionEnabled"));
   }
 
   disable_composition_ = options.disable_effects();
 }
 
 ScreenCapturerWinGdi::~ScreenCapturerWinGdi() {
-  if (desktop_dc_)
-    ReleaseDC(NULL, desktop_dc_);
-  if (memory_dc_)
-    DeleteDC(memory_dc_);
-
-  if (disable_composition_) {
-    // Restore Aero.
-    if (composition_func_)
-      (*composition_func_)(DWM_EC_ENABLECOMPOSITION);
-  }
+  Stop();
 
   if (dwmapi_library_)
     FreeLibrary(dwmapi_library_);
 }
 
 void ScreenCapturerWinGdi::Capture(const DesktopRegion& region) {
   assert(IsGUIThread(false));
   TickTime capture_start_time = TickTime::Now();
@@ -160,16 +151,34 @@ void ScreenCapturerWinGdi::Start(Callbac
     // Vote to disable Aero composited desktop effects while capturing. Windows
     // will restore Aero automatically if the process exits. This has no effect
     // under Windows 8 or higher.  See crbug.com/124018.
     if (composition_func_)
       (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
   }
 }
 
+void ScreenCapturerWinGdi::Stop() {
+  if (desktop_dc_) {
+    ReleaseDC(NULL, desktop_dc_);
+    desktop_dc_ = NULL;
+  }
+  if (memory_dc_) {
+    DeleteDC(memory_dc_);
+    memory_dc_ = NULL;
+  }
+
+  if (disable_composition_) {
+    // Restore Aero.
+    if (composition_func_)
+      (*composition_func_)(DWM_EC_ENABLECOMPOSITION);
+  }
+  callback_ = NULL;
+}
+
 void ScreenCapturerWinGdi::PrepareCaptureResources() {
   assert(IsGUIThread(false));
   // Switch to the desktop receiving user input if different from the current
   // one.
   rtc::scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
   if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
     // Release GDI resources otherwise SetThreadDesktop will fail.
     if (desktop_dc_) {
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h
@@ -29,16 +29,17 @@ class Differ;
 // ScreenCapturerWinGdi is double-buffered as required by ScreenCapturer.
 class ScreenCapturerWinGdi : public ScreenCapturer {
  public:
   explicit ScreenCapturerWinGdi(const DesktopCaptureOptions& options);
   virtual ~ScreenCapturerWinGdi();
 
   // Overridden from ScreenCapturer:
   void Start(Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
   bool GetScreenList(ScreenList* screens) override;
   bool SelectScreen(ScreenId id) override;
 
  private:
   typedef HRESULT (WINAPI * DwmEnableCompositionFunc)(UINT);
   typedef HRESULT (WINAPI * DwmIsCompositionEnabledFunc)(BOOL*);
 
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
@@ -52,39 +52,53 @@ ScreenCapturerWinMagnifier::ScreenCaptur
       set_image_scaling_callback_func_(NULL),
       host_window_(NULL),
       magnifier_window_(NULL),
       magnifier_initialized_(false),
       magnifier_capture_succeeded_(true) {
 }
 
 ScreenCapturerWinMagnifier::~ScreenCapturerWinMagnifier() {
-  // DestroyWindow must be called before MagUninitialize. magnifier_window_ is
-  // destroyed automatically when host_window_ is destroyed.
-  if (host_window_)
-    DestroyWindow(host_window_);
-
-  if (magnifier_initialized_)
-    mag_uninitialize_func_();
-
-  if (mag_lib_handle_)
-    FreeLibrary(mag_lib_handle_);
-
-  if (desktop_dc_)
-    ReleaseDC(NULL, desktop_dc_);
+  Stop();
 }
 
 void ScreenCapturerWinMagnifier::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
   callback_ = callback;
 
   InitializeMagnifier();
 }
 
+void ScreenCapturerWinMagnifier::Stop() {
+  callback_ = NULL;
+
+  // DestroyWindow must be called before MagUninitialize. magnifier_window_ is
+  // destroyed automatically when host_window_ is destroyed.
+  if (host_window_) {
+    DestroyWindow(host_window_);
+    host_window_ = NULL;
+  }
+
+  if (magnifier_initialized_) {
+    mag_uninitialize_func_();
+    magnifier_initialized_ = false;
+  }
+
+  if (mag_lib_handle_) {
+    FreeLibrary(mag_lib_handle_);
+    mag_lib_handle_ = NULL;
+  }
+
+  if (desktop_dc_) {
+    ReleaseDC(NULL, desktop_dc_);
+    desktop_dc_ = NULL;
+  }
+}
+
 void ScreenCapturerWinMagnifier::Capture(const DesktopRegion& region) {
   TickTime capture_start_time = TickTime::Now();
 
   queue_.MoveToNextFrame();
 
   // Request that the system not power-down the system, or the display hardware.
   if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) {
     if (!set_thread_execution_state_failed_) {
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h
@@ -39,16 +39,17 @@ class ScreenCapturerWinMagnifier : publi
   // screen is being captured, or the OS does not support Magnification API, or
   // the magnifier capturer fails (e.g. in Windows8 Metro mode).
   explicit ScreenCapturerWinMagnifier(
       rtc::scoped_ptr<ScreenCapturer> fallback_capturer);
   virtual ~ScreenCapturerWinMagnifier();
 
   // Overridden from ScreenCapturer:
   void Start(Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
   bool GetScreenList(ScreenList* screens) override;
   bool SelectScreen(ScreenId id) override;
   void SetExcludedWindow(WindowId window) override;
 
  private:
   typedef BOOL(WINAPI* MagImageScalingCallback)(HWND hwnd,
                                                 void* srcdata,
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_mac.mm
@@ -51,16 +51,17 @@ class WindowCapturerMac : public WindowC
 
   // WindowCapturer interface.
   bool GetWindowList(WindowList* windows) override;
   bool SelectWindow(WindowId id) override;
   bool BringSelectedWindowToFront() override;
 
   // DesktopCapturer interface.
   void Start(Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
 
  private:
   Callback* callback_;
 
   // The window being captured.
   CGWindowID window_id_;
 
@@ -182,16 +183,20 @@ bool WindowCapturerMac::BringSelectedWin
 
 void WindowCapturerMac::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
 
+void WindowCapturerMac::Stop() {
+  callback_ = NULL;
+}
+
 void WindowCapturerMac::Capture(const DesktopRegion& region) {
   if (!IsWindowValid(window_id_)) {
     callback_->OnCaptureCompleted(NULL);
     return;
   }
 
   CGWindowID on_screen_window = window_id_;
   if (full_screen_chrome_window_detector_) {
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_null.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_null.cc
@@ -25,16 +25,17 @@ class WindowCapturerNull : public Window
 
   // WindowCapturer interface.
   bool GetWindowList(WindowList* windows) override;
   bool SelectWindow(WindowId id) override;
   bool BringSelectedWindowToFront() override;
 
   // DesktopCapturer interface.
   void Start(Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
 
  private:
   Callback* callback_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowCapturerNull);
 };
 
@@ -62,16 +63,20 @@ bool WindowCapturerNull::BringSelectedWi
 
 void WindowCapturerNull::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
 
+void WindowCapturerNull::Stop() {
+  callback_ = NULL;
+}
+
 void WindowCapturerNull::Capture(const DesktopRegion& region) {
   // Not implemented yet.
   callback_->OnCaptureCompleted(NULL);
 }
 
 }  // namespace
 
 // static
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_win.cc
@@ -89,16 +89,17 @@ class WindowCapturerWin : public WindowC
 
   // WindowCapturer interface.
   bool GetWindowList(WindowList* windows) override;
   bool SelectWindow(WindowId id) override;
   bool BringSelectedWindowToFront() override;
 
   // DesktopCapturer interface.
   void Start(Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
 
  private:
   bool IsAeroEnabled();
 
   Callback* callback_;
 
   // HWND and HDC for the currently selected window or NULL if window is not
@@ -174,16 +175,20 @@ bool WindowCapturerWin::BringSelectedWin
 
 void WindowCapturerWin::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
 
+void WindowCapturerWin::Stop() {
+  callback_ = NULL;
+}
+
 void WindowCapturerWin::Capture(const DesktopRegion& region) {
   assert(IsGUIThread(false));
   if (!window_) {
     LOG(LS_ERROR) << "Window hasn't been selected: " << GetLastError();
     callback_->OnCaptureCompleted(NULL);
     return;
   }
 
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc
@@ -41,16 +41,17 @@ class WindowCapturerLinux : public Windo
 
   // WindowCapturer interface.
   bool GetWindowList(WindowList* windows) override;
   bool SelectWindow(WindowId id) override;
   bool BringSelectedWindowToFront() override;
 
   // DesktopCapturer interface.
   void Start(Callback* callback) override;
+  void Stop() override;
   void Capture(const DesktopRegion& region) override;
 
   // SharedXDisplay::XEventHandler interface.
   bool HandleXEvent(const XEvent& event) override;
 
  private:
   Display* display() { return x_display_->display(); }
 
@@ -230,16 +231,20 @@ bool WindowCapturerLinux::BringSelectedW
 
 void WindowCapturerLinux::Start(Callback* callback) {
   assert(!callback_);
   assert(callback);
 
   callback_ = callback;
 }
 
+void WindowCapturerLinux::Stop() {
+  callback_ = NULL;
+}
+
 void WindowCapturerLinux::Capture(const DesktopRegion& region) {
   x_display_->ProcessPendingXEvents();
 
   if (!x_server_pixel_buffer_.IsWindowValid()) {
     LOG(LS_INFO) << "The window is no longer valid.";
     callback_->OnCaptureCompleted(NULL);
     return;
   }
--- a/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
@@ -467,20 +467,21 @@ DesktopCaptureImpl::DesktopCaptureImpl(c
     _lastProcessFrameCount(TickTime::Now()),
     _rotateFrame(kVideoRotation_0),
   last_capture_time_(TickTime::MillisecondTimestamp()),
   delta_ntp_internal_ms_(
                          Clock::GetRealTimeClock()->CurrentNtpInMilliseconds() -
                          TickTime::MillisecondTimestamp()),
   time_event_(EventWrapper::Create()),
 #if defined(_WIN32)
-  capturer_thread_(ThreadWrapper::CreateUIThread(Run, this, "ScreenCaptureThread")) {
+  capturer_thread_(ThreadWrapper::CreateUIThread(Run, this, "ScreenCaptureThread")),
 #else
-  capturer_thread_(ThreadWrapper::CreateThread(Run, this, "ScreenCaptureThread")) {
+  capturer_thread_(ThreadWrapper::CreateThread(Run, this, "ScreenCaptureThread")),
 #endif
+  started_(false) {
   capturer_thread_->SetPriority(kHighPriority);
   _requestedCapability.width = kDefaultWidth;
   _requestedCapability.height = kDefaultHeight;
   _requestedCapability.maxFPS = 30;
   _requestedCapability.rawType = kVideoI420;
   _requestedCapability.codecType = kVideoCodecUnknown;
   memset(_incomingFrameTimes, 0, sizeof(_incomingFrameTimes));
 }
@@ -778,26 +779,33 @@ int32_t DesktopCaptureImpl::StartCapture
   _requestedCapability = capability;
 #if defined(_WIN32)
   uint32_t maxFPSNeeded = 1000/_requestedCapability.maxFPS;
   capturer_thread_->RequestCallbackTimer(maxFPSNeeded);
 #endif
 
   desktop_capturer_cursor_composer_->Start(this);
   capturer_thread_->Start();
+  started_ = true;
 
   return 0;
 }
 
 int32_t DesktopCaptureImpl::StopCapture() {
+  if (started_) {
+    capturer_thread_->Stop(); // thread is guaranteed stopped before this returns
+    desktop_capturer_cursor_composer_->Stop();
+    started_ = false;
+    return 0;
+  }
   return -1;
 }
 
 bool DesktopCaptureImpl::CaptureStarted() {
-  return false;
+  return started_;
 }
 
 int32_t DesktopCaptureImpl::CaptureSettings(VideoCaptureCapability& settings) {
   return -1;
 }
 
 void DesktopCaptureImpl::OnCaptureCompleted(DesktopFrame* frame) {
   if (frame == NULL) return;
--- a/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.h
+++ b/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.h
@@ -256,13 +256,14 @@ public:
     return true;
   };
   void process();
 
 private:
   rtc::scoped_ptr<DesktopAndCursorComposer> desktop_capturer_cursor_composer_;
   rtc::scoped_ptr<EventWrapper> time_event_;
   rtc::scoped_ptr<ThreadWrapper> capturer_thread_;
+  bool started_;
 };
 
 }  // namespace webrtc
 
 #endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_MAIN_SOURCE_DESKTOP_CAPTURE_IMPL_H_