Implement single monitor capture on Mac.
BUG=2787, 2824 TESTED=MacBook Pro Retina with an external monitor; verified changing display configuration while capturing; add/remove monitor while capturing; verified cursor position. R=sergeyu@chromium.org Review URL: https://webrtc-codereview.appspot.com/7479004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5471 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
83aee8f450
commit
1af5ea0538
@ -38,6 +38,8 @@
|
||||
"mac/desktop_configuration.mm",
|
||||
"mac/desktop_configuration_monitor.h",
|
||||
"mac/desktop_configuration_monitor.cc",
|
||||
"mac/osx_version.h",
|
||||
"mac/osx_version.cc",
|
||||
"mac/scoped_pixel_buffer_object.cc",
|
||||
"mac/scoped_pixel_buffer_object.h",
|
||||
"mouse_cursor.cc",
|
||||
|
||||
@ -26,7 +26,11 @@ typedef intptr_t WindowId;
|
||||
|
||||
const WindowId kNullWindowId = 0;
|
||||
|
||||
typedef int ScreenId;
|
||||
// Type used to identify screens on the desktop. Values are platform-specific:
|
||||
// - On Windows: integer display device index.
|
||||
// - On OSX: CGDirectDisplayID cast to intptr_t.
|
||||
// - On Linux (with X11): TBD.
|
||||
typedef intptr_t ScreenId;
|
||||
|
||||
// The screen id corresponds to all screen combined together.
|
||||
const ScreenId kFullDesktopScreenId = -1;
|
||||
|
||||
@ -55,6 +55,10 @@ struct MacDesktopConfiguration {
|
||||
// Returns true if the given desktop configuration equals this one.
|
||||
bool Equals(const MacDesktopConfiguration& other);
|
||||
|
||||
// Returns the pointer to the display configuration with the specified id.
|
||||
const MacDisplayConfiguration* FindDisplayConfigurationById(
|
||||
CGDirectDisplayID id);
|
||||
|
||||
// Bounds of the desktop in Density-Independent Pixels (DIPs).
|
||||
DesktopRect bounds;
|
||||
|
||||
|
||||
@ -110,15 +110,8 @@ MacDesktopConfiguration MacDesktopConfiguration::GetCurrent(Origin origin) {
|
||||
MacDisplayConfiguration display_config =
|
||||
GetConfigurationForScreen([screens objectAtIndex: i]);
|
||||
|
||||
// Handling mixed-DPI is hard, so we only return displays that match the
|
||||
// "primary" display's DPI. The primary display is always the first in the
|
||||
// list returned by [NSScreen screens].
|
||||
if (i == 0) {
|
||||
if (i == 0)
|
||||
desktop_config.dip_to_pixel_scale = display_config.dip_to_pixel_scale;
|
||||
} else if (desktop_config.dip_to_pixel_scale !=
|
||||
display_config.dip_to_pixel_scale) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cocoa uses bottom-up coordinates, so if the caller wants top-down then
|
||||
// we need to invert the positions of secondary monitors relative to the
|
||||
@ -126,8 +119,16 @@ MacDesktopConfiguration MacDesktopConfiguration::GetCurrent(Origin origin) {
|
||||
if (i > 0 && origin == TopLeftOrigin) {
|
||||
InvertRectYOrigin(desktop_config.displays[0].bounds,
|
||||
&display_config.bounds);
|
||||
InvertRectYOrigin(desktop_config.displays[0].pixel_bounds,
|
||||
&display_config.pixel_bounds);
|
||||
// |display_bounds| is density dependent, so we need to convert the
|
||||
// primay monitor's position into the secondary monitor's density context.
|
||||
float scaling_factor = display_config.dip_to_pixel_scale /
|
||||
desktop_config.displays[0].dip_to_pixel_scale;
|
||||
DesktopRect primary_bounds = DesktopRect::MakeLTRB(
|
||||
desktop_config.displays[0].pixel_bounds.left() * scaling_factor,
|
||||
desktop_config.displays[0].pixel_bounds.top() * scaling_factor,
|
||||
desktop_config.displays[0].pixel_bounds.right() * scaling_factor,
|
||||
desktop_config.displays[0].pixel_bounds.bottom() * scaling_factor);
|
||||
InvertRectYOrigin(primary_bounds, &display_config.pixel_bounds);
|
||||
}
|
||||
|
||||
// Add the display to the configuration.
|
||||
@ -143,7 +144,6 @@ MacDesktopConfiguration MacDesktopConfiguration::GetCurrent(Origin origin) {
|
||||
return desktop_config;
|
||||
}
|
||||
|
||||
|
||||
// For convenience of comparing MacDisplayConfigurations in
|
||||
// MacDesktopConfiguration::Equals.
|
||||
bool operator==(const MacDisplayConfiguration& left,
|
||||
@ -161,4 +161,16 @@ bool MacDesktopConfiguration::Equals(const MacDesktopConfiguration& other) {
|
||||
displays == other.displays;
|
||||
}
|
||||
|
||||
// Finds the display configuration with the specified id.
|
||||
const MacDisplayConfiguration*
|
||||
MacDesktopConfiguration::FindDisplayConfigurationById(
|
||||
CGDirectDisplayID id) {
|
||||
for (MacDisplayConfigurations::const_iterator it = displays.begin();
|
||||
it != displays.end(); ++it) {
|
||||
if (it->id == id)
|
||||
return &(*it);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
54
webrtc/modules/desktop_capture/mac/osx_version.cc
Normal file
54
webrtc/modules/desktop_capture/mac/osx_version.cc
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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 <sys/utsname.h>
|
||||
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
int GetDarwinVersion() {
|
||||
struct utsname uname_info;
|
||||
if (uname(&uname_info) != 0) {
|
||||
LOG(LS_ERROR) << "uname failed";
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// Darwin major version 11 corresponds to OSX 10.7.
|
||||
return darwin_version >= 11;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
16
webrtc/modules/desktop_capture/mac/osx_version.h
Normal file
16
webrtc/modules/desktop_capture/mac/osx_version.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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.
|
||||
*/
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Returns true if the OS version >= OSX 10.7.
|
||||
bool IsOSLionOrLater();
|
||||
|
||||
} // namespace webrtc
|
||||
@ -17,8 +17,11 @@
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame.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/mouse_cursor.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_refptr.h"
|
||||
|
||||
@ -27,31 +30,44 @@ namespace webrtc {
|
||||
class MouseCursorMonitorMac : public MouseCursorMonitor {
|
||||
public:
|
||||
MouseCursorMonitorMac(const DesktopCaptureOptions& options,
|
||||
CGWindowID window_id);
|
||||
CGWindowID window_id,
|
||||
ScreenId screen_id);
|
||||
virtual ~MouseCursorMonitorMac();
|
||||
|
||||
virtual void Init(Callback* callback, Mode mode) OVERRIDE;
|
||||
virtual void Capture() OVERRIDE;
|
||||
|
||||
private:
|
||||
static void DisplaysReconfiguredCallback(CGDirectDisplayID display,
|
||||
CGDisplayChangeSummaryFlags flags,
|
||||
void *user_parameter);
|
||||
void DisplaysReconfigured(CGDirectDisplayID display,
|
||||
CGDisplayChangeSummaryFlags flags);
|
||||
|
||||
void CaptureImage();
|
||||
|
||||
scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
|
||||
CGWindowID window_id_;
|
||||
|
||||
ScreenId screen_id_;
|
||||
Callback* callback_;
|
||||
Mode mode_;
|
||||
|
||||
scoped_ptr<MouseCursor> last_cursor_;
|
||||
};
|
||||
|
||||
MouseCursorMonitorMac::MouseCursorMonitorMac(
|
||||
const DesktopCaptureOptions& options,
|
||||
CGWindowID window_id)
|
||||
CGWindowID window_id,
|
||||
ScreenId screen_id)
|
||||
: configuration_monitor_(options.configuration_monitor()),
|
||||
window_id_(window_id),
|
||||
screen_id_(screen_id),
|
||||
callback_(NULL),
|
||||
mode_(SHAPE_AND_POSITION) {
|
||||
assert(window_id == kCGNullWindowID || screen_id == kInvalidScreenId);
|
||||
if (screen_id != kInvalidScreenId && !IsOSLionOrLater()) {
|
||||
// Single screen capture is not supported on pre OS X 10.7.
|
||||
screen_id_ = kFullDesktopScreenId;
|
||||
}
|
||||
}
|
||||
|
||||
MouseCursorMonitorMac::~MouseCursorMonitorMac() {}
|
||||
@ -80,6 +96,21 @@ void MouseCursorMonitorMac::Capture() {
|
||||
|
||||
DesktopVector position(gc_position.x, gc_position.y);
|
||||
|
||||
configuration_monitor_->Lock();
|
||||
MacDesktopConfiguration configuration =
|
||||
configuration_monitor_->desktop_configuration();
|
||||
configuration_monitor_->Unlock();
|
||||
float scale = 1.0f;
|
||||
|
||||
// Find the dpi to physical pixel scale for the screen where the mouse cursor
|
||||
// is.
|
||||
for (MacDisplayConfigurations::iterator it = configuration.displays.begin();
|
||||
it != configuration.displays.end(); ++it) {
|
||||
if (it->bounds.Contains(position)) {
|
||||
scale = it->dip_to_pixel_scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If we are capturing cursor for a specific window then we need to figure out
|
||||
// if the current mouse position is covered by another window and also adjust
|
||||
// |position| to make it relative to the window origin.
|
||||
@ -142,10 +173,8 @@ void MouseCursorMonitorMac::Capture() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(window_array);
|
||||
}
|
||||
|
||||
if (!found_window) {
|
||||
// If we failed to get list of windows or the window wasn't in the list
|
||||
// pretend that the cursor is outside the window. This can happen, e.g. if
|
||||
@ -153,17 +182,32 @@ void MouseCursorMonitorMac::Capture() {
|
||||
state = OUTSIDE;
|
||||
position.set(-1, -1);
|
||||
}
|
||||
} else {
|
||||
assert(screen_id_ >= kFullDesktopScreenId);
|
||||
if (screen_id_ != kFullDesktopScreenId) {
|
||||
// For single screen capturing, convert the position to relative to the
|
||||
// target screen.
|
||||
const MacDisplayConfiguration* config =
|
||||
configuration.FindDisplayConfigurationById(
|
||||
static_cast<CGDirectDisplayID>(screen_id_));
|
||||
if (config) {
|
||||
if (!config->pixel_bounds.Contains(position))
|
||||
state = OUTSIDE;
|
||||
position = position.subtract(config->bounds.top_left());
|
||||
} else {
|
||||
// The target screen is no longer valid.
|
||||
state = OUTSIDE;
|
||||
position.set(-1, -1);
|
||||
}
|
||||
} else {
|
||||
position.subtract(configuration.bounds.top_left());
|
||||
}
|
||||
}
|
||||
if (state == INSIDE) {
|
||||
// Convert Density Independent Pixel to physical pixel.
|
||||
position = DesktopVector(round(position.x() * scale),
|
||||
round(position.y() * scale));
|
||||
}
|
||||
|
||||
// Convert Density Independent Pixel to physical pixel.
|
||||
configuration_monitor_->Lock();
|
||||
float scale =
|
||||
configuration_monitor_->desktop_configuration().dip_to_pixel_scale;
|
||||
configuration_monitor_->Unlock();
|
||||
|
||||
position = DesktopVector(round(position.x() * scale),
|
||||
round(position.y() * scale));
|
||||
|
||||
callback_->OnMouseCursorPosition(state, position);
|
||||
}
|
||||
|
||||
@ -221,16 +265,15 @@ void MouseCursorMonitorMac::CaptureImage() {
|
||||
callback_->OnMouseCursor(cursor.release());
|
||||
}
|
||||
|
||||
|
||||
MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
|
||||
const DesktopCaptureOptions& options, WindowId window) {
|
||||
return new MouseCursorMonitorMac(options, window);
|
||||
return new MouseCursorMonitorMac(options, window, kInvalidScreenId);
|
||||
}
|
||||
|
||||
MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
|
||||
const DesktopCaptureOptions& options,
|
||||
ScreenId screen) {
|
||||
return new MouseCursorMonitorMac(options, kCGNullWindowID);
|
||||
return new MouseCursorMonitorMac(options, kCGNullWindowID, screen);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
#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"
|
||||
@ -27,6 +26,7 @@
|
||||
#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"
|
||||
@ -87,39 +87,6 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// Darwin major version 11 corresponds to OSX 10.7.
|
||||
return darwin_version >= 11;
|
||||
}
|
||||
|
||||
// A class to perform video frame capturing for mac.
|
||||
class ScreenCapturerMac : public ScreenCapturer {
|
||||
public:
|
||||
@ -145,7 +112,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.
|
||||
@ -167,6 +135,8 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
void *user_parameter);
|
||||
void ReleaseBuffers();
|
||||
|
||||
DesktopFrame* CreateFrame();
|
||||
|
||||
Callback* callback_;
|
||||
MouseShapeObserver* mouse_shape_observer_;
|
||||
|
||||
@ -176,6 +146,19 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
// Queue of the frames buffers.
|
||||
ScreenCaptureFrameQueue queue_;
|
||||
|
||||
// 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_;
|
||||
@ -189,10 +172,6 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
// Monitoring display reconfiguration.
|
||||
scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor_;
|
||||
|
||||
// The desktop configuration obtained from desktop_config_monitor_ the last
|
||||
// time of capturing.
|
||||
MacDesktopConfiguration desktop_config_;
|
||||
|
||||
// Power management assertion to prevent the screen from sleeping.
|
||||
IOPMAssertionID power_assertion_id_display_;
|
||||
|
||||
@ -233,24 +212,13 @@ 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(
|
||||
scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor)
|
||||
: callback_(NULL),
|
||||
mouse_shape_observer_(NULL),
|
||||
cgl_context_(NULL),
|
||||
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),
|
||||
@ -282,6 +250,9 @@ bool ScreenCapturerMac::Init() {
|
||||
if (!RegisterRefreshAndMoveHandlers()) {
|
||||
return false;
|
||||
}
|
||||
desktop_config_monitor_->Lock();
|
||||
desktop_config_ = desktop_config_monitor_->desktop_configuration();
|
||||
desktop_config_monitor_->Unlock();
|
||||
ScreenConfigurationChanged();
|
||||
return true;
|
||||
}
|
||||
@ -346,7 +317,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();
|
||||
|
||||
@ -354,7 +325,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) {
|
||||
@ -397,15 +371,42 @@ void ScreenCapturerMac::SetMouseShapeObserver(
|
||||
|
||||
bool ScreenCapturerMac::GetScreenList(ScreenList* screens) {
|
||||
assert(screens->size() == 0);
|
||||
// TODO(jiayl): implement screen enumeration.
|
||||
Screen default_screen;
|
||||
default_screen.id = 0;
|
||||
screens->push_back(default_screen);
|
||||
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) {
|
||||
// TODO(jiayl): implement screen selection.
|
||||
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;
|
||||
}
|
||||
|
||||
@ -602,7 +603,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
|
||||
@ -613,13 +614,37 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -662,9 +687,20 @@ void ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
|
||||
CFRelease(data);
|
||||
CFRelease(image);
|
||||
}
|
||||
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();
|
||||
|
||||
@ -672,7 +708,7 @@ void ScreenCapturerMac::ScreenConfigurationChanged() {
|
||||
helper_.ClearInvalidRegion();
|
||||
|
||||
// Re-mark the entire desktop as dirty.
|
||||
helper_.InvalidateScreen(desktop_config_.pixel_bounds.size());
|
||||
helper_.InvalidateScreen(screen_pixel_bounds_.size());
|
||||
|
||||
// Make sure the frame buffers will be reallocated.
|
||||
queue_.Reset();
|
||||
@ -753,8 +789,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);
|
||||
}
|
||||
@ -786,20 +822,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);
|
||||
}
|
||||
|
||||
@ -824,7 +857,7 @@ void ScreenCapturerMac::ScreenRefreshCallback(CGRectCount count,
|
||||
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);
|
||||
}
|
||||
@ -839,6 +872,15 @@ void ScreenCapturerMac::ScreenUpdateMoveCallback(
|
||||
capturer->ScreenUpdateMove(delta, count, rect_array);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user