Makes ScreenCapturerMac exclude the window specified in DesktopCapturer::SetExcludedWindow.
No behavior change for now since Chromium has not been updated to call SetExcludedWindow. BUG=2789 R=sergeyu@chromium.org Review URL: https://webrtc-codereview.appspot.com/10299004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5792 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
4e65602886
commit
7ee0c16edd
@ -142,6 +142,10 @@ void DesktopAndCursorComposer::Capture(const DesktopRegion& region) {
|
||||
desktop_capturer_->Capture(region);
|
||||
}
|
||||
|
||||
void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) {
|
||||
desktop_capturer_->SetExcludedWindow(window);
|
||||
}
|
||||
|
||||
SharedMemory* DesktopAndCursorComposer::CreateSharedMemory(size_t size) {
|
||||
return callback_->CreateSharedMemory(size);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ class DesktopAndCursorComposer : public DesktopCapturer,
|
||||
// DesktopCapturer interface.
|
||||
virtual void Start(DesktopCapturer::Callback* callback) OVERRIDE;
|
||||
virtual void Capture(const DesktopRegion& region) OVERRIDE;
|
||||
virtual void SetExcludedWindow(WindowId window) OVERRIDE;
|
||||
|
||||
private:
|
||||
// DesktopCapturer::Callback interface.
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class DesktopFrame;
|
||||
@ -52,6 +54,11 @@ class DesktopCapturer {
|
||||
// the top left corner of the capture target. Pending capture operations are
|
||||
// canceled when DesktopCapturer is deleted.
|
||||
virtual void Capture(const DesktopRegion& region) = 0;
|
||||
|
||||
// Sets the window to be excluded from the captured image in the future
|
||||
// Capture calls. Used to exclude the screenshare notification window for
|
||||
// screen capturing.
|
||||
virtual void SetExcludedWindow(WindowId window) {}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -63,7 +63,8 @@ DesktopRect ScaleAndRoundCGRect(const CGRect& rect, float scale) {
|
||||
static_cast<int>(ceil((rect.origin.y + rect.size.height) * scale)));
|
||||
}
|
||||
|
||||
// Copy pixels in the |rect| from |src_place| to |dest_plane|.
|
||||
// Copy pixels in the |rect| from |src_place| to |dest_plane|. |rect| should be
|
||||
// relative to the origin of |src_plane| and |dest_plane|.
|
||||
void CopyRect(const uint8_t* src_plane,
|
||||
int src_plane_stride,
|
||||
uint8_t* dest_plane,
|
||||
@ -87,6 +88,105 @@ void CopyRect(const uint8_t* src_plane,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns an array of CGWindowID for all the on-screen windows except
|
||||
// |window_to_exclude|, or NULL if the window is not found or it fails. The
|
||||
// caller should release the returned CFArrayRef.
|
||||
CFArrayRef CreateWindowListWithExclusion(CGWindowID window_to_exclude) {
|
||||
if (!window_to_exclude)
|
||||
return NULL;
|
||||
|
||||
CFArrayRef all_windows = CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||
if (!all_windows)
|
||||
return NULL;
|
||||
|
||||
CFMutableArrayRef returned_array = CFArrayCreateMutable(
|
||||
NULL, CFArrayGetCount(all_windows), NULL);
|
||||
|
||||
bool found = false;
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(all_windows); ++i) {
|
||||
CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
|
||||
CFArrayGetValueAtIndex(all_windows, i));
|
||||
|
||||
CFNumberRef id_ref = reinterpret_cast<CFNumberRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowNumber));
|
||||
|
||||
CGWindowID id;
|
||||
CFNumberGetValue(id_ref, kCFNumberIntType, &id);
|
||||
if (id == window_to_exclude) {
|
||||
found = true;
|
||||
continue;
|
||||
}
|
||||
CFArrayAppendValue(returned_array, reinterpret_cast<void *>(id));
|
||||
}
|
||||
CFRelease(all_windows);
|
||||
|
||||
if (!found) {
|
||||
CFRelease(returned_array);
|
||||
returned_array = NULL;
|
||||
}
|
||||
return returned_array;
|
||||
}
|
||||
|
||||
// Returns the bounds of |window| in physical pixels, enlarged by a small amount
|
||||
// on four edges to take account of the border/shadow effects.
|
||||
DesktopRect GetExcludedWindowPixelBounds(CGWindowID window,
|
||||
float dip_to_pixel_scale) {
|
||||
// The amount of pixels to add to the actual window bounds to take into
|
||||
// account of the border/shadow effects.
|
||||
static const int kBorderEffectSize = 20;
|
||||
CGRect rect;
|
||||
CGWindowID ids[1];
|
||||
ids[0] = window;
|
||||
|
||||
CFArrayRef window_id_array =
|
||||
CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
|
||||
CFArrayRef window_array =
|
||||
CGWindowListCreateDescriptionFromArray(window_id_array);
|
||||
|
||||
if (CFArrayGetCount(window_array) > 0) {
|
||||
CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
|
||||
CFArrayGetValueAtIndex(window_array, 0));
|
||||
CFDictionaryRef bounds_ref = reinterpret_cast<CFDictionaryRef>(
|
||||
CFDictionaryGetValue(window, kCGWindowBounds));
|
||||
CGRectMakeWithDictionaryRepresentation(bounds_ref, &rect);
|
||||
}
|
||||
|
||||
CFRelease(window_id_array);
|
||||
CFRelease(window_array);
|
||||
|
||||
rect.origin.x -= kBorderEffectSize;
|
||||
rect.origin.y -= kBorderEffectSize;
|
||||
rect.size.width += kBorderEffectSize * 2;
|
||||
rect.size.height += kBorderEffectSize * 2;
|
||||
// |rect| is in DIP, so convert to physical pixels.
|
||||
return ScaleAndRoundCGRect(rect, dip_to_pixel_scale);
|
||||
}
|
||||
|
||||
// Create an image of the given region using the given |window_list|.
|
||||
// |pixel_bounds| should be in the primary display's coordinate in physical
|
||||
// pixels. The caller should release the returned CGImageRef and CFDataRef.
|
||||
CGImageRef CreateExcludedWindowRegionImage(const DesktopRect& pixel_bounds,
|
||||
float dip_to_pixel_scale,
|
||||
CFArrayRef window_list,
|
||||
CFDataRef* data_ref) {
|
||||
CGRect window_bounds;
|
||||
// The origin is in DIP while the size is in physical pixels. That's what
|
||||
// CGWindowListCreateImageFromArray expects.
|
||||
window_bounds.origin.x = pixel_bounds.left() / dip_to_pixel_scale;
|
||||
window_bounds.origin.y = pixel_bounds.top() / dip_to_pixel_scale;
|
||||
window_bounds.size.width = pixel_bounds.width();
|
||||
window_bounds.size.height = pixel_bounds.height();
|
||||
|
||||
CGImageRef excluded_image = CGWindowListCreateImageFromArray(
|
||||
window_bounds, window_list, kCGWindowImageDefault);
|
||||
|
||||
CGDataProviderRef provider = CGImageGetDataProvider(excluded_image);
|
||||
*data_ref = CGDataProviderCopyData(provider);
|
||||
assert(*data_ref);
|
||||
return excluded_image;
|
||||
}
|
||||
|
||||
// A class to perform video frame capturing for mac.
|
||||
class ScreenCapturerMac : public ScreenCapturer {
|
||||
public:
|
||||
@ -99,6 +199,7 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
// Overridden from ScreenCapturer:
|
||||
virtual void Start(Callback* callback) OVERRIDE;
|
||||
virtual void Capture(const DesktopRegion& region) OVERRIDE;
|
||||
virtual void SetExcludedWindow(WindowId window) OVERRIDE;
|
||||
virtual void SetMouseShapeObserver(
|
||||
MouseShapeObserver* mouse_shape_observer) OVERRIDE;
|
||||
virtual bool GetScreenList(ScreenList* screens) OVERRIDE;
|
||||
@ -186,6 +287,8 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
void* opengl_library_;
|
||||
CGLSetFullScreenFunc cgl_set_full_screen_;
|
||||
|
||||
CGWindowID excluded_window_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac);
|
||||
};
|
||||
|
||||
@ -227,7 +330,8 @@ ScreenCapturerMac::ScreenCapturerMac(
|
||||
cg_display_bytes_per_row_(NULL),
|
||||
cg_display_bits_per_pixel_(NULL),
|
||||
opengl_library_(NULL),
|
||||
cgl_set_full_screen_(NULL) {
|
||||
cgl_set_full_screen_(NULL),
|
||||
excluded_window_(0) {
|
||||
}
|
||||
|
||||
ScreenCapturerMac::~ScreenCapturerMac() {
|
||||
@ -291,8 +395,7 @@ void ScreenCapturerMac::Start(Callback* callback) {
|
||||
&power_assertion_id_user_);
|
||||
}
|
||||
|
||||
void ScreenCapturerMac::Capture(
|
||||
const DesktopRegion& region_to_capture) {
|
||||
void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) {
|
||||
TickTime capture_start_time = TickTime::Now();
|
||||
|
||||
queue_.MoveToNextFrame();
|
||||
@ -362,6 +465,10 @@ void ScreenCapturerMac::Capture(
|
||||
callback_->OnCaptureCompleted(new_frame);
|
||||
}
|
||||
|
||||
void ScreenCapturerMac::SetExcludedWindow(WindowId window) {
|
||||
excluded_window_ = window;
|
||||
}
|
||||
|
||||
void ScreenCapturerMac::SetMouseShapeObserver(
|
||||
MouseShapeObserver* mouse_shape_observer) {
|
||||
assert(!mouse_shape_observer_);
|
||||
@ -631,6 +738,9 @@ bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
|
||||
displays_to_capture = desktop_config_.displays;
|
||||
}
|
||||
|
||||
// Create the window list once for all displays.
|
||||
CFArrayRef window_list = CreateWindowListWithExclusion(excluded_window_);
|
||||
|
||||
for (size_t i = 0; i < displays_to_capture.size(); ++i) {
|
||||
const MacDisplayConfiguration& display_config = displays_to_capture[i];
|
||||
|
||||
@ -655,6 +765,26 @@ bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
|
||||
// Translate the region to be copied into display-relative coordinates.
|
||||
copy_region.Translate(-display_bounds.left(), -display_bounds.top());
|
||||
|
||||
DesktopRect excluded_window_bounds;
|
||||
CGImageRef excluded_image = NULL;
|
||||
CFDataRef excluded_window_region_data = NULL;
|
||||
if (excluded_window_ && window_list) {
|
||||
// Get the region of the excluded window relative the primary display.
|
||||
excluded_window_bounds = GetExcludedWindowPixelBounds(
|
||||
excluded_window_, display_config.dip_to_pixel_scale);
|
||||
excluded_window_bounds.IntersectWith(display_config.pixel_bounds);
|
||||
|
||||
// Create the image under the excluded window first, because it's faster
|
||||
// than captuing the whole display.
|
||||
if (!excluded_window_bounds.is_empty()) {
|
||||
excluded_image = CreateExcludedWindowRegionImage(
|
||||
excluded_window_bounds,
|
||||
display_config.dip_to_pixel_scale,
|
||||
window_list,
|
||||
&excluded_window_region_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Create an image containing a snapshot of the display.
|
||||
CGImageRef image = CGDisplayCreateImage(display_config.id);
|
||||
if (image == NULL)
|
||||
@ -684,9 +814,36 @@ bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
|
||||
i.rect());
|
||||
}
|
||||
|
||||
// Copy the region of the excluded window to the frame.
|
||||
if (excluded_image) {
|
||||
assert(excluded_window_region_data);
|
||||
display_base_address = CFDataGetBytePtr(excluded_window_region_data);
|
||||
src_bytes_per_row = CGImageGetBytesPerRow(excluded_image);
|
||||
|
||||
// Translate the bounds relative to the desktop, because |frame| data
|
||||
// starts from the desktop top-left corner.
|
||||
DesktopRect window_bounds_relative_to_desktop(excluded_window_bounds);
|
||||
window_bounds_relative_to_desktop.Translate(
|
||||
-screen_pixel_bounds_.left(), -screen_pixel_bounds_.top());
|
||||
out_ptr = frame.data() +
|
||||
(window_bounds_relative_to_desktop.left() * src_bytes_per_pixel) +
|
||||
(window_bounds_relative_to_desktop.top() * frame.stride());
|
||||
|
||||
CopyRect(display_base_address,
|
||||
src_bytes_per_row,
|
||||
out_ptr,
|
||||
frame.stride(),
|
||||
src_bytes_per_pixel,
|
||||
DesktopRect::MakeSize(excluded_window_bounds.size()));
|
||||
CFRelease(excluded_window_region_data);
|
||||
CFRelease(excluded_image);
|
||||
}
|
||||
|
||||
CFRelease(data);
|
||||
CFRelease(image);
|
||||
}
|
||||
if (window_list)
|
||||
CFRelease(window_list);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user