From cc1ba15fe737bfc58ef279d50d7e713cbd8b9310 Mon Sep 17 00:00:00 2001 From: "jiayl@webrtc.org" Date: Thu, 24 Apr 2014 23:45:56 +0000 Subject: [PATCH] Returns a NULL frame on all platforms if the captured window is closed. Part of the fix for crbug/360181. On Mac/Linux, it previously continues capturing even if the window is closed. Now it stops by returning a NULL frame. On Windows, it used to stop capturing when the window is minimized. Now fixed to match other platforms. Note: the crbug still needs a chrome side fix to close the notification bar. This fix only stops the stream (i.e. stream onended event fired). BUG=crbug/360181 TESTED=manually tested in Chrome R=sergeyu@chromium.org Review URL: https://webrtc-codereview.appspot.com/12329007 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5977 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../desktop_capture/window_capturer_mac.mm | 33 ++++++++++--------- .../desktop_capture/window_capturer_win.cc | 4 +-- .../desktop_capture/window_capturer_x11.cc | 6 ++++ .../x11/x_server_pixel_buffer.cc | 12 +++++++ .../x11/x_server_pixel_buffer.h | 3 ++ 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/webrtc/modules/desktop_capture/window_capturer_mac.mm b/webrtc/modules/desktop_capture/window_capturer_mac.mm index 3ceae31ec7..d177fc40c7 100644 --- a/webrtc/modules/desktop_capture/window_capturer_mac.mm +++ b/webrtc/modules/desktop_capture/window_capturer_mac.mm @@ -42,6 +42,18 @@ bool CFStringRefToUtf8(const CFStringRef string, std::string* str_utf8) { return true; } +bool IsWindowValid(CGWindowID id) { + CFArrayRef window_id_array = + CFArrayCreate(NULL, reinterpret_cast(&id), 1, NULL); + CFArrayRef window_array = + CGWindowListCreateDescriptionFromArray(window_id_array); + bool valid = window_array && CFArrayGetCount(window_array); + CFRelease(window_id_array); + CFRelease(window_array); + + return valid; +} + class WindowCapturerMac : public WindowCapturer { public: WindowCapturerMac(); @@ -115,22 +127,8 @@ bool WindowCapturerMac::GetWindowList(WindowList* windows) { } bool WindowCapturerMac::SelectWindow(WindowId id) { - // Request description for the specified window to make sure |id| is valid. - CGWindowID ids[1]; - ids[0] = id; - CFArrayRef window_id_array = - CFArrayCreate(NULL, reinterpret_cast(&ids), 1, NULL); - CFArrayRef window_array = - CGWindowListCreateDescriptionFromArray(window_id_array); - int results_count = window_array ? CFArrayGetCount(window_array) : 0; - CFRelease(window_id_array); - CFRelease(window_array); - - if (results_count == 0) { - // Could not find the window. It might have been closed. + if (!IsWindowValid(id)) return false; - } - window_id_ = id; return true; } @@ -180,6 +178,11 @@ void WindowCapturerMac::Start(Callback* callback) { } void WindowCapturerMac::Capture(const DesktopRegion& region) { + if (!IsWindowValid(window_id_)) { + callback_->OnCaptureCompleted(NULL); + return; + } + CGImageRef window_image = CGWindowListCreateImage( CGRectNull, kCGWindowListOptionIncludingWindow, window_id_, kCGWindowImageBoundsIgnoreFraming); diff --git a/webrtc/modules/desktop_capture/window_capturer_win.cc b/webrtc/modules/desktop_capture/window_capturer_win.cc index b9764b3a45..a002185620 100644 --- a/webrtc/modules/desktop_capture/window_capturer_win.cc +++ b/webrtc/modules/desktop_capture/window_capturer_win.cc @@ -182,8 +182,8 @@ void WindowCapturerWin::Capture(const DesktopRegion& region) { return; } - // Stop capturing if the window has been minimized or hidden. - if (IsIconic(window_) || !IsWindowVisible(window_)) { + // Stop capturing if the window has been closed or hidden. + if (!IsWindow(window_) || !IsWindowVisible(window_)) { callback_->OnCaptureCompleted(NULL); return; } diff --git a/webrtc/modules/desktop_capture/window_capturer_x11.cc b/webrtc/modules/desktop_capture/window_capturer_x11.cc index baeb894b35..b641c93218 100755 --- a/webrtc/modules/desktop_capture/window_capturer_x11.cc +++ b/webrtc/modules/desktop_capture/window_capturer_x11.cc @@ -278,6 +278,12 @@ void WindowCapturerLinux::Start(Callback* callback) { } void WindowCapturerLinux::Capture(const DesktopRegion& region) { + if (!x_server_pixel_buffer_.IsWindowValid()) { + LOG(LS_INFO) << "The window is no longer valid."; + callback_->OnCaptureCompleted(NULL); + return; + } + x_display_->ProcessPendingXEvents(); if (!has_composite_extension_) { diff --git a/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc b/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc index 6983a6dcce..be00fa7697 100644 --- a/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc +++ b/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc @@ -213,6 +213,18 @@ bool XServerPixelBuffer::InitPixmaps(int depth) { return true; } +bool XServerPixelBuffer::IsWindowValid() const { + XWindowAttributes attributes; + { + XErrorTrap error_trap(display_); + if (!XGetWindowAttributes(display_, window_, &attributes) || + error_trap.GetLastErrorAndDisable() != 0) { + return false; + } + } + return true; +} + void XServerPixelBuffer::Synchronize() { if (shm_segment_info_ && !shm_pixmap_) { // XShmGetImage can fail if the display is being reconfigured. diff --git a/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h b/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h index b81096c811..98f263f3a8 100644 --- a/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h +++ b/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h @@ -40,6 +40,9 @@ class XServerPixelBuffer { // Returns the size of the window the buffer was initialized for. const DesktopSize& window_size() { return window_size_; } + // Returns true if the window can be found. + bool IsWindowValid() const; + // If shared memory is being used without pixmaps, synchronize this pixel // buffer with the root window contents (otherwise, this is a no-op). // This is to avoid doing a full-screen capture for each individual