summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_mac.mm')
-rw-r--r--chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_mac.mm451
1 files changed, 300 insertions, 151 deletions
diff --git a/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_mac.mm b/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_mac.mm
index 00639c73918..2d5733906f0 100644
--- a/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_mac.mm
+++ b/chromium/third_party/webrtc/modules/desktop_capture/screen_capturer_mac.mm
@@ -19,18 +19,18 @@
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <OpenGL/CGLMacro.h>
#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"
#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
+#include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h"
+#include "webrtc/modules/desktop_capture/mac/osx_version.h"
#include "webrtc/modules/desktop_capture/mac/scoped_pixel_buffer_object.h"
#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
-#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
@@ -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,46 +88,110 @@ void CopyRect(const uint8_t* src_plane,
}
}
-int GetDarwinVersion() {
- struct utsname uname_info;
- if (uname(&uname_info) != 0) {
- LOG(LS_ERROR) << "uname failed";
- return 0;
+// 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 (strcmp(uname_info.sysname, "Darwin") != 0)
- return 0;
-
- char* dot;
- int result = strtol(uname_info.release, &dot, 10);
- if (*dot != '.') {
- LOG(LS_ERROR) << "Failed to parse version";
- return 0;
+ if (!found) {
+ CFRelease(returned_array);
+ returned_array = NULL;
}
-
- return result;
+ return returned_array;
}
-bool IsOSLionOrLater() {
- static int darwin_version = GetDarwinVersion();
-
- // Verify that the version has been parsed correctly.
- if (darwin_version < 6) {
- LOG_F(LS_ERROR) << "Invalid Darwin version: " << darwin_version;
- abort();
+// 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);
}
- // Darwin major version 11 corresponds to OSX 10.7.
- return darwin_version >= 11;
+ 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);
}
-// The amount of time allowed for displays to reconfigure.
-const int64_t kDisplayConfigurationEventTimeoutMs = 10 * 1000;
+// 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:
- ScreenCapturerMac();
+ explicit ScreenCapturerMac(
+ scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor);
virtual ~ScreenCapturerMac();
bool Init();
@@ -134,8 +199,11 @@ 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;
+ virtual bool SelectScreen(ScreenId id) OVERRIDE;
private:
void CaptureCursor();
@@ -145,7 +213,8 @@ class ScreenCapturerMac : public ScreenCapturer {
void GlBlitSlow(const DesktopFrame& frame);
void CgBlitPreLion(const DesktopFrame& frame,
const DesktopRegion& region);
- void CgBlitPostLion(const DesktopFrame& frame,
+ // Returns false if the selected screen is no longer valid.
+ bool CgBlitPostLion(const DesktopFrame& frame,
const DesktopRegion& region);
// Called when the screen configuration is changed.
@@ -158,8 +227,6 @@ class ScreenCapturerMac : public ScreenCapturer {
void ScreenUpdateMove(CGScreenUpdateMoveDelta delta,
size_t count,
const CGRect *rect_array);
- void DisplaysReconfigured(CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags);
static void ScreenRefreshCallback(CGRectCount count,
const CGRect *rect_array,
void *user_parameter);
@@ -167,12 +234,10 @@ class ScreenCapturerMac : public ScreenCapturer {
size_t count,
const CGRect *rect_array,
void *user_parameter);
- static void DisplaysReconfiguredCallback(CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags,
- void *user_parameter);
-
void ReleaseBuffers();
+ DesktopFrame* CreateFrame();
+
Callback* callback_;
MouseShapeObserver* mouse_shape_observer_;
@@ -185,6 +250,16 @@ class ScreenCapturerMac : public ScreenCapturer {
// Current display configuration.
MacDesktopConfiguration desktop_config_;
+ // Currently selected display, or 0 if the full desktop is selected. On OS X
+ // 10.6 and before, this is always 0.
+ CGDirectDisplayID current_display_;
+
+ // The physical pixel bounds of the current screen.
+ DesktopRect screen_pixel_bounds_;
+
+ // The dip to physical pixel scale of the current screen.
+ float dip_to_pixel_scale_;
+
// A thread-safe list of invalid rectangles, and the size of the most
// recently captured screen.
ScreenCapturerHelper helper_;
@@ -195,13 +270,8 @@ class ScreenCapturerMac : public ScreenCapturer {
// Contains an invalid region from the previous capture.
DesktopRegion last_invalid_region_;
- // Used to ensure that frame captures do not take place while displays
- // are being reconfigured.
- scoped_ptr<EventWrapper> display_configuration_capture_event_;
-
- // Records the Ids of attached displays which are being reconfigured.
- // Accessed on the thread on which we are notified of display events.
- std::set<CGDirectDisplayID> reconfiguring_displays_;
+ // Monitoring display reconfiguration.
+ scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor_;
// Power management assertion to prevent the screen from sleeping.
IOPMAssertionID power_assertion_id_display_;
@@ -217,6 +287,8 @@ class ScreenCapturerMac : public ScreenCapturer {
void* opengl_library_;
CGLSetFullScreenFunc cgl_set_full_screen_;
+ CGWindowID excluded_window_;
+
DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac);
};
@@ -243,24 +315,14 @@ class InvertedDesktopFrame : public DesktopFrame {
DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame);
};
-DesktopFrame* CreateFrame(
- const MacDesktopConfiguration& desktop_config) {
-
- DesktopSize size(desktop_config.pixel_bounds.width(),
- desktop_config.pixel_bounds.height());
- scoped_ptr<DesktopFrame> frame(new BasicDesktopFrame(size));
-
- frame->set_dpi(DesktopVector(
- kStandardDPI * desktop_config.dip_to_pixel_scale,
- kStandardDPI * desktop_config.dip_to_pixel_scale));
- return frame.release();
-}
-
-ScreenCapturerMac::ScreenCapturerMac()
+ScreenCapturerMac::ScreenCapturerMac(
+ scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor)
: callback_(NULL),
mouse_shape_observer_(NULL),
cgl_context_(NULL),
- display_configuration_capture_event_(EventWrapper::Create()),
+ current_display_(0),
+ dip_to_pixel_scale_(1.0f),
+ desktop_config_monitor_(desktop_config_monitor),
power_assertion_id_display_(kIOPMNullAssertionID),
power_assertion_id_user_(kIOPMNullAssertionID),
app_services_library_(NULL),
@@ -268,8 +330,8 @@ ScreenCapturerMac::ScreenCapturerMac()
cg_display_bytes_per_row_(NULL),
cg_display_bits_per_pixel_(NULL),
opengl_library_(NULL),
- cgl_set_full_screen_(NULL) {
- display_configuration_capture_event_->Set();
+ cgl_set_full_screen_(NULL),
+ excluded_window_(0) {
}
ScreenCapturerMac::~ScreenCapturerMac() {
@@ -284,11 +346,6 @@ ScreenCapturerMac::~ScreenCapturerMac() {
ReleaseBuffers();
UnregisterRefreshAndMoveHandlers();
- CGError err = CGDisplayRemoveReconfigurationCallback(
- ScreenCapturerMac::DisplaysReconfiguredCallback, this);
- if (err != kCGErrorSuccess)
- LOG(LS_ERROR) << "CGDisplayRemoveReconfigurationCallback " << err;
-
dlclose(app_services_library_);
dlclose(opengl_library_);
}
@@ -297,14 +354,9 @@ bool ScreenCapturerMac::Init() {
if (!RegisterRefreshAndMoveHandlers()) {
return false;
}
-
- CGError err = CGDisplayRegisterReconfigurationCallback(
- ScreenCapturerMac::DisplaysReconfiguredCallback, this);
- if (err != kCGErrorSuccess) {
- LOG(LS_ERROR) << "CGDisplayRegisterReconfigurationCallback " << err;
- return false;
- }
-
+ desktop_config_monitor_->Lock();
+ desktop_config_ = desktop_config_monitor_->desktop_configuration();
+ desktop_config_monitor_->Unlock();
ScreenConfigurationChanged();
return true;
}
@@ -343,20 +395,22 @@ 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();
- // Wait until the display configuration is stable. If one or more displays
- // are reconfiguring then |display_configuration_capture_event_| will not be
- // set until the reconfiguration completes.
- // TODO(wez): Replace this with an early-exit (See crbug.com/104542).
- if (!display_configuration_capture_event_->Wait(
- kDisplayConfigurationEventTimeoutMs)) {
- LOG_F(LS_ERROR) << "Event wait timed out.";
- abort();
+ desktop_config_monitor_->Lock();
+ MacDesktopConfiguration new_config =
+ desktop_config_monitor_->desktop_configuration();
+ if (!desktop_config_.Equals(new_config)) {
+ desktop_config_ = new_config;
+ // If the display configuraiton has changed then refresh capturer data
+ // structures. Occasionally, the refresh and move handlers are lost when
+ // the screen mode changes, so re-register them here.
+ UnregisterRefreshAndMoveHandlers();
+ RegisterRefreshAndMoveHandlers();
+ ScreenConfigurationChanged();
}
DesktopRegion region;
@@ -366,7 +420,7 @@ void ScreenCapturerMac::Capture(
// Note that we can't reallocate other buffers at this point, since the caller
// may still be reading from them.
if (!queue_.current_frame())
- queue_.ReplaceCurrentFrame(CreateFrame(desktop_config_));
+ queue_.ReplaceCurrentFrame(CreateFrame());
DesktopFrame* current_frame = queue_.current_frame();
@@ -374,7 +428,10 @@ void ScreenCapturerMac::Capture(
if (IsOSLionOrLater()) {
// Lion requires us to use their new APIs for doing screen capture. These
// APIS currently crash on 10.6.8 if there is no monitor attached.
- CgBlitPostLion(*current_frame, region);
+ if (!CgBlitPostLion(*current_frame, region)) {
+ callback_->OnCaptureCompleted(NULL);
+ return;
+ }
} else if (cgl_context_) {
flip = true;
if (pixel_buffer_object_.get() != 0) {
@@ -398,7 +455,7 @@ void ScreenCapturerMac::Capture(
// Signal that we are done capturing data from the display framebuffer,
// and accessing display structures.
- display_configuration_capture_event_->Set();
+ desktop_config_monitor_->Unlock();
// Capture the current cursor shape and notify |callback_| if it has changed.
CaptureCursor();
@@ -408,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_);
@@ -415,6 +476,47 @@ void ScreenCapturerMac::SetMouseShapeObserver(
mouse_shape_observer_ = mouse_shape_observer;
}
+bool ScreenCapturerMac::GetScreenList(ScreenList* screens) {
+ assert(screens->size() == 0);
+ if (!IsOSLionOrLater()) {
+ // Single monitor cast is not supported on pre OS X 10.7.
+ Screen screen;
+ screen.id = kFullDesktopScreenId;
+ screens->push_back(screen);
+ return true;
+ }
+
+ for (MacDisplayConfigurations::iterator it = desktop_config_.displays.begin();
+ it != desktop_config_.displays.end(); ++it) {
+ Screen screen;
+ screen.id = static_cast<ScreenId>(it->id);
+ screens->push_back(screen);
+ }
+ return true;
+}
+
+bool ScreenCapturerMac::SelectScreen(ScreenId id) {
+ if (!IsOSLionOrLater()) {
+ // Ignore the screen selection on unsupported OS.
+ assert(!current_display_);
+ return id == kFullDesktopScreenId;
+ }
+
+ if (id == kFullDesktopScreenId) {
+ current_display_ = 0;
+ } else {
+ const MacDisplayConfiguration* config =
+ desktop_config_.FindDisplayConfigurationById(
+ static_cast<CGDirectDisplayID>(id));
+ if (!config)
+ return false;
+ current_display_ = config->id;
+ }
+
+ ScreenConfigurationChanged();
+ return true;
+}
+
void ScreenCapturerMac::CaptureCursor() {
if (!mouse_shape_observer_)
return;
@@ -608,7 +710,7 @@ void ScreenCapturerMac::CgBlitPreLion(const DesktopFrame& frame,
}
}
-void ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
+bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
const DesktopRegion& region) {
// Copy the entire contents of the previous capture buffer, to capture over.
// TODO(wez): Get rid of this as per crbug.com/145064, or implement
@@ -619,13 +721,40 @@ void ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
frame.stride() * frame.size().height());
}
- for (size_t i = 0; i < desktop_config_.displays.size(); ++i) {
- const MacDisplayConfiguration& display_config = desktop_config_.displays[i];
+ MacDisplayConfigurations displays_to_capture;
+ if (current_display_) {
+ // Capturing a single screen. Note that the screen id may change when
+ // screens are added or removed.
+ const MacDisplayConfiguration* config =
+ desktop_config_.FindDisplayConfigurationById(current_display_);
+ if (config) {
+ displays_to_capture.push_back(*config);
+ } else {
+ LOG(LS_ERROR) << "The selected screen cannot be found for capturing.";
+ return false;
+ }
+ } else {
+ // Capturing the whole desktop.
+ 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];
+
+ // Capturing mixed-DPI on one surface is hard, so we only return displays
+ // that match the "primary" display's DPI. The primary display is always
+ // the first in the list.
+ if (i > 0 && display_config.dip_to_pixel_scale !=
+ displays_to_capture[0].dip_to_pixel_scale) {
+ continue;
+ }
// Determine the display's position relative to the desktop, in pixels.
DesktopRect display_bounds = display_config.pixel_bounds;
- display_bounds.Translate(-desktop_config_.pixel_bounds.left(),
- -desktop_config_.pixel_bounds.top());
+ display_bounds.Translate(-screen_pixel_bounds_.left(),
+ -screen_pixel_bounds_.top());
// Determine which parts of the blit region, if any, lay within the monitor.
DesktopRegion copy_region = region;
@@ -636,6 +765,26 @@ void 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)
@@ -665,26 +814,58 @@ void 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;
}
void ScreenCapturerMac::ScreenConfigurationChanged() {
+ if (current_display_) {
+ const MacDisplayConfiguration* config =
+ desktop_config_.FindDisplayConfigurationById(current_display_);
+ screen_pixel_bounds_ = config ? config->pixel_bounds : DesktopRect();
+ dip_to_pixel_scale_ = config ? config->dip_to_pixel_scale : 1.0f;
+ } else {
+ screen_pixel_bounds_ = desktop_config_.pixel_bounds;
+ dip_to_pixel_scale_ = desktop_config_.dip_to_pixel_scale;
+ }
+
// Release existing buffers, which will be of the wrong size.
ReleaseBuffers();
// Clear the dirty region, in case the display is down-sizing.
helper_.ClearInvalidRegion();
- // Refresh the cached desktop configuration.
- desktop_config_ = MacDesktopConfiguration::GetCurrent(
- MacDesktopConfiguration::TopLeftOrigin);
-
// Re-mark the entire desktop as dirty.
- helper_.InvalidateScreen(
- DesktopSize(desktop_config_.pixel_bounds.width(),
- desktop_config_.pixel_bounds.height()));
+ helper_.InvalidateScreen(screen_pixel_bounds_.size());
// Make sure the frame buffers will be reallocated.
queue_.Reset();
@@ -765,8 +946,8 @@ void ScreenCapturerMac::ScreenConfigurationChanged() {
(*cgl_set_full_screen_)(cgl_context_);
CGLSetCurrentContext(cgl_context_);
- size_t buffer_size = desktop_config_.pixel_bounds.width() *
- desktop_config_.pixel_bounds.height() *
+ size_t buffer_size = screen_pixel_bounds_.width() *
+ screen_pixel_bounds_.height() *
sizeof(uint32_t);
pixel_buffer_object_.Init(cgl_context_, buffer_size);
}
@@ -798,20 +979,17 @@ void ScreenCapturerMac::UnregisterRefreshAndMoveHandlers() {
void ScreenCapturerMac::ScreenRefresh(CGRectCount count,
const CGRect* rect_array) {
- if (desktop_config_.pixel_bounds.is_empty())
+ if (screen_pixel_bounds_.is_empty())
return;
DesktopRegion region;
-
+ DesktopVector translate_vector =
+ DesktopVector().subtract(screen_pixel_bounds_.top_left());
for (CGRectCount i = 0; i < count; ++i) {
// Convert from Density-Independent Pixel to physical pixel coordinates.
- DesktopRect rect =
- ScaleAndRoundCGRect(rect_array[i], desktop_config_.dip_to_pixel_scale);
-
+ DesktopRect rect = ScaleAndRoundCGRect(rect_array[i], dip_to_pixel_scale_);
// Translate from local desktop to capturer framebuffer coordinates.
- rect.Translate(-desktop_config_.pixel_bounds.left(),
- -desktop_config_.pixel_bounds.top());
-
+ rect.Translate(translate_vector);
region.AddRect(rect);
}
@@ -831,45 +1009,12 @@ void ScreenCapturerMac::ScreenUpdateMove(CGScreenUpdateMoveDelta delta,
ScreenRefresh(count, refresh_rects);
}
-void ScreenCapturerMac::DisplaysReconfigured(
- CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags) {
- if (flags & kCGDisplayBeginConfigurationFlag) {
- if (reconfiguring_displays_.empty()) {
- // If this is the first display to start reconfiguring then wait on
- // |display_configuration_capture_event_| to block the capture thread
- // from accessing display memory until the reconfiguration completes.
- if (!display_configuration_capture_event_->Wait(
- kDisplayConfigurationEventTimeoutMs)) {
- LOG_F(LS_ERROR) << "Event wait timed out.";
- abort();
- }
- }
-
- reconfiguring_displays_.insert(display);
- } else {
- reconfiguring_displays_.erase(display);
-
- if (reconfiguring_displays_.empty()) {
- // If no other displays are reconfiguring then refresh capturer data
- // structures and un-block the capturer thread. Occasionally, the
- // refresh and move handlers are lost when the screen mode changes,
- // so re-register them here (the same does not appear to be true for
- // the reconfiguration handler itself).
- UnregisterRefreshAndMoveHandlers();
- RegisterRefreshAndMoveHandlers();
- ScreenConfigurationChanged();
- display_configuration_capture_event_->Set();
- }
- }
-}
-
void ScreenCapturerMac::ScreenRefreshCallback(CGRectCount count,
const CGRect* rect_array,
void* user_parameter) {
ScreenCapturerMac* capturer =
reinterpret_cast<ScreenCapturerMac*>(user_parameter);
- if (capturer->desktop_config_.pixel_bounds.is_empty())
+ if (capturer->screen_pixel_bounds_.is_empty())
capturer->ScreenConfigurationChanged();
capturer->ScreenRefresh(count, rect_array);
}
@@ -884,20 +1029,24 @@ void ScreenCapturerMac::ScreenUpdateMoveCallback(
capturer->ScreenUpdateMove(delta, count, rect_array);
}
-void ScreenCapturerMac::DisplaysReconfiguredCallback(
- CGDirectDisplayID display,
- CGDisplayChangeSummaryFlags flags,
- void* user_parameter) {
- ScreenCapturerMac* capturer =
- reinterpret_cast<ScreenCapturerMac*>(user_parameter);
- capturer->DisplaysReconfigured(display, flags);
+DesktopFrame* ScreenCapturerMac::CreateFrame() {
+ scoped_ptr<DesktopFrame> frame(
+ new BasicDesktopFrame(screen_pixel_bounds_.size()));
+
+ frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_,
+ kStandardDPI * dip_to_pixel_scale_));
+ return frame.release();
}
} // namespace
// static
ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
- scoped_ptr<ScreenCapturerMac> capturer(new ScreenCapturerMac());
+ if (!options.configuration_monitor())
+ return NULL;
+
+ scoped_ptr<ScreenCapturerMac> capturer(
+ new ScreenCapturerMac(options.configuration_monitor()));
if (!capturer->Init())
capturer.reset();
return capturer.release();