Fix screen capturers to initialize on the same thread on which Start() is called.
Previously screen capturers were initialized when they are created. This means that in the CRD host they were initialized on the thread that's different from the thread on which they are used. Because of this on Linux the host was using XErrorTrap() on two different threads and this is not supported. Now ScreenCapturer implementations always initialize themselves on the thread on which Start() is called. Also added ThreadChecker to make sure the capturers are always called from the same thread. BUG=600432 Review URL: https://codereview.webrtc.org/1861893002 Cr-Commit-Position: refs/heads/master@{#12285}
This commit is contained in:
parent
aad6780e5c
commit
e8d4b7d8a3
@ -33,6 +33,9 @@ class DesktopCapturer {
|
||||
// from chromium.
|
||||
virtual SharedMemory* CreateSharedMemory(size_t size) { return nullptr; }
|
||||
|
||||
// Called to notify that the capturer has failed to initialize.
|
||||
virtual void OnInitializationFailed() {};
|
||||
|
||||
// Called after a frame has been captured. Handler must take ownership of
|
||||
// |frame|. If capture has failed for any reason |frame| is set to NULL
|
||||
// (e.g. the window has been closed).
|
||||
|
||||
@ -22,7 +22,9 @@
|
||||
#include <OpenGL/CGLMacro.h>
|
||||
#include <OpenGL/OpenGL.h>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/macutils.h"
|
||||
#include "webrtc/base/thread_checker.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"
|
||||
@ -188,8 +190,6 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor);
|
||||
virtual ~ScreenCapturerMac();
|
||||
|
||||
bool Init();
|
||||
|
||||
// Overridden from ScreenCapturer:
|
||||
void Start(Callback* callback) override;
|
||||
void Capture(const DesktopRegion& region) override;
|
||||
@ -198,6 +198,8 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
bool SelectScreen(ScreenId id) override;
|
||||
|
||||
private:
|
||||
bool Initialize();
|
||||
|
||||
void GlBlitFast(const DesktopFrame& frame,
|
||||
const DesktopRegion& region);
|
||||
void GlBlitSlow(const DesktopFrame& frame);
|
||||
@ -228,9 +230,11 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
|
||||
DesktopFrame* CreateFrame();
|
||||
|
||||
Callback* callback_;
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
|
||||
CGLContextObj cgl_context_;
|
||||
Callback* callback_ = nullptr;
|
||||
|
||||
CGLContextObj cgl_context_ = nullptr;
|
||||
ScopedPixelBufferObject pixel_buffer_object_;
|
||||
|
||||
// Queue of the frames buffers.
|
||||
@ -241,13 +245,13 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
|
||||
// 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_;
|
||||
CGDirectDisplayID current_display_ = 0;
|
||||
|
||||
// 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_;
|
||||
float dip_to_pixel_scale_ = 1.0f;
|
||||
|
||||
// A thread-safe list of invalid rectangles, and the size of the most
|
||||
// recently captured screen.
|
||||
@ -260,20 +264,20 @@ class ScreenCapturerMac : public ScreenCapturer {
|
||||
rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor_;
|
||||
|
||||
// Power management assertion to prevent the screen from sleeping.
|
||||
IOPMAssertionID power_assertion_id_display_;
|
||||
IOPMAssertionID power_assertion_id_display_ = kIOPMNullAssertionID;
|
||||
|
||||
// Power management assertion to indicate that the user is active.
|
||||
IOPMAssertionID power_assertion_id_user_;
|
||||
IOPMAssertionID power_assertion_id_user_ = kIOPMNullAssertionID;
|
||||
|
||||
// Dynamically link to deprecated APIs for Mac OS X 10.6 support.
|
||||
void* app_services_library_;
|
||||
CGDisplayBaseAddressFunc cg_display_base_address_;
|
||||
CGDisplayBytesPerRowFunc cg_display_bytes_per_row_;
|
||||
CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_;
|
||||
void* opengl_library_;
|
||||
CGLSetFullScreenFunc cgl_set_full_screen_;
|
||||
void* app_services_library_ = nullptr;
|
||||
CGDisplayBaseAddressFunc cg_display_base_address_ = nullptr;
|
||||
CGDisplayBytesPerRowFunc cg_display_bytes_per_row_ = nullptr;
|
||||
CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_ = nullptr;
|
||||
void* opengl_library_ = nullptr;
|
||||
CGLSetFullScreenFunc cgl_set_full_screen_ = nullptr;
|
||||
|
||||
CGWindowID excluded_window_;
|
||||
CGWindowID excluded_window_ = 0;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac);
|
||||
};
|
||||
@ -303,23 +307,15 @@ class InvertedDesktopFrame : public DesktopFrame {
|
||||
|
||||
ScreenCapturerMac::ScreenCapturerMac(
|
||||
rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor)
|
||||
: callback_(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),
|
||||
app_services_library_(NULL),
|
||||
cg_display_base_address_(NULL),
|
||||
cg_display_bytes_per_row_(NULL),
|
||||
cg_display_bits_per_pixel_(NULL),
|
||||
opengl_library_(NULL),
|
||||
cgl_set_full_screen_(NULL),
|
||||
excluded_window_(0) {
|
||||
: desktop_config_monitor_(desktop_config_monitor) {
|
||||
// ScreenCapturer can be used on a thread different from the thread on which
|
||||
// it's created.
|
||||
thread_checker_.DetachFromThread();
|
||||
}
|
||||
|
||||
ScreenCapturerMac::~ScreenCapturerMac() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
|
||||
if (power_assertion_id_display_ != kIOPMNullAssertionID) {
|
||||
IOPMAssertionRelease(power_assertion_id_display_);
|
||||
power_assertion_id_display_ = kIOPMNullAssertionID;
|
||||
@ -335,7 +331,7 @@ ScreenCapturerMac::~ScreenCapturerMac() {
|
||||
dlclose(opengl_library_);
|
||||
}
|
||||
|
||||
bool ScreenCapturerMac::Init() {
|
||||
bool ScreenCapturerMac::Initialize() {
|
||||
if (!RegisterRefreshAndMoveHandlers()) {
|
||||
return false;
|
||||
}
|
||||
@ -359,11 +355,17 @@ void ScreenCapturerMac::ReleaseBuffers() {
|
||||
}
|
||||
|
||||
void ScreenCapturerMac::Start(Callback* callback) {
|
||||
assert(!callback_);
|
||||
assert(callback);
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(!callback_);
|
||||
RTC_DCHECK(callback);
|
||||
|
||||
callback_ = callback;
|
||||
|
||||
if (!Initialize()) {
|
||||
callback_->OnInitializationFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create power management assertions to wake the display and prevent it from
|
||||
// going to sleep on user idle.
|
||||
// TODO(jamiewalch): Use IOPMAssertionDeclareUserActivity on 10.7.3 and above
|
||||
@ -381,6 +383,8 @@ void ScreenCapturerMac::Start(Callback* callback) {
|
||||
}
|
||||
|
||||
void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
|
||||
TickTime capture_start_time = TickTime::Now();
|
||||
|
||||
queue_.MoveToNextFrame();
|
||||
@ -449,11 +453,14 @@ void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) {
|
||||
}
|
||||
|
||||
void ScreenCapturerMac::SetExcludedWindow(WindowId window) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
excluded_window_ = window;
|
||||
}
|
||||
|
||||
bool ScreenCapturerMac::GetScreenList(ScreenList* screens) {
|
||||
assert(screens->size() == 0);
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(screens->size() == 0);
|
||||
|
||||
if (rtc::GetOSVersionName() < rtc::kMacOSLion) {
|
||||
// Single monitor cast is not supported on pre OS X 10.7.
|
||||
Screen screen;
|
||||
@ -472,6 +479,8 @@ bool ScreenCapturerMac::GetScreenList(ScreenList* screens) {
|
||||
}
|
||||
|
||||
bool ScreenCapturerMac::SelectScreen(ScreenId id) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
|
||||
if (rtc::GetOSVersionName() < rtc::kMacOSLion) {
|
||||
// Ignore the screen selection on unsupported OS.
|
||||
assert(!current_display_);
|
||||
@ -980,11 +989,7 @@ ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
|
||||
if (!options.configuration_monitor())
|
||||
return NULL;
|
||||
|
||||
std::unique_ptr<ScreenCapturerMac> capturer(
|
||||
new ScreenCapturerMac(options.configuration_monitor()));
|
||||
if (!capturer->Init())
|
||||
capturer.reset();
|
||||
return capturer.release();
|
||||
return new ScreenCapturerMac(options.configuration_monitor());
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/thread_checker.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||
#include "webrtc/modules/desktop_capture/differ.h"
|
||||
@ -37,12 +38,9 @@ namespace {
|
||||
class ScreenCapturerLinux : public ScreenCapturer,
|
||||
public SharedXDisplay::XEventHandler {
|
||||
public:
|
||||
ScreenCapturerLinux();
|
||||
explicit ScreenCapturerLinux(const DesktopCaptureOptions& options);
|
||||
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 Capture(const DesktopRegion& region) override;
|
||||
@ -54,11 +52,13 @@ class ScreenCapturerLinux : public ScreenCapturer,
|
||||
private:
|
||||
Display* display() { return options_.x_display()->display(); }
|
||||
|
||||
// SharedXDisplay::XEventHandler interface.
|
||||
bool HandleXEvent(const XEvent& event) override;
|
||||
bool Initialize();
|
||||
|
||||
void InitXDamage();
|
||||
|
||||
// SharedXDisplay::XEventHandler interface.
|
||||
bool HandleXEvent(const XEvent& event) override;
|
||||
|
||||
// Capture screen pixels to the current buffer in the queue. In the DAMAGE
|
||||
// case, the ScreenCapturerHelper already holds the list of invalid rectangles
|
||||
// from HandleXEvent(). In the non-DAMAGE case, this captures the
|
||||
@ -78,25 +78,27 @@ class ScreenCapturerLinux : public ScreenCapturer,
|
||||
|
||||
void DeinitXlib();
|
||||
|
||||
rtc::ThreadChecker thread_checker_;
|
||||
|
||||
DesktopCaptureOptions options_;
|
||||
|
||||
Callback* callback_;
|
||||
Callback* callback_ = nullptr;
|
||||
|
||||
// X11 graphics context.
|
||||
GC gc_;
|
||||
Window root_window_;
|
||||
GC gc_ = nullptr;
|
||||
Window root_window_ = BadValue;
|
||||
|
||||
// XFixes.
|
||||
bool has_xfixes_;
|
||||
int xfixes_event_base_;
|
||||
int xfixes_error_base_;
|
||||
bool has_xfixes_ = false;
|
||||
int xfixes_event_base_ = -1;
|
||||
int xfixes_error_base_ = -1;
|
||||
|
||||
// XDamage information.
|
||||
bool use_damage_;
|
||||
Damage damage_handle_;
|
||||
int damage_event_base_;
|
||||
int damage_error_base_;
|
||||
XserverRegion damage_region_;
|
||||
bool use_damage_ = false;
|
||||
Damage damage_handle_ = 0;
|
||||
int damage_event_base_ = -1;
|
||||
int damage_error_base_ = -1;
|
||||
XserverRegion damage_region_ = 0;
|
||||
|
||||
// Access to the X Server's pixel buffer.
|
||||
XServerPixelBuffer x_server_pixel_buffer_;
|
||||
@ -118,22 +120,16 @@ class ScreenCapturerLinux : public ScreenCapturer,
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
|
||||
};
|
||||
|
||||
ScreenCapturerLinux::ScreenCapturerLinux()
|
||||
: callback_(NULL),
|
||||
gc_(NULL),
|
||||
root_window_(BadValue),
|
||||
has_xfixes_(false),
|
||||
xfixes_event_base_(-1),
|
||||
xfixes_error_base_(-1),
|
||||
use_damage_(false),
|
||||
damage_handle_(0),
|
||||
damage_event_base_(-1),
|
||||
damage_error_base_(-1),
|
||||
damage_region_(0) {
|
||||
helper_.SetLogGridSize(4);
|
||||
ScreenCapturerLinux::ScreenCapturerLinux(const DesktopCaptureOptions& options)
|
||||
: options_(options) {
|
||||
// ScreenCapturer can be used on a thread different from the thread on which
|
||||
// it's created.
|
||||
thread_checker_.DetachFromThread();
|
||||
}
|
||||
|
||||
ScreenCapturerLinux::~ScreenCapturerLinux() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
|
||||
options_.x_display()->RemoveEventHandler(ConfigureNotify, this);
|
||||
if (use_damage_) {
|
||||
options_.x_display()->RemoveEventHandler(
|
||||
@ -142,8 +138,8 @@ ScreenCapturerLinux::~ScreenCapturerLinux() {
|
||||
DeinitXlib();
|
||||
}
|
||||
|
||||
bool ScreenCapturerLinux::Init(const DesktopCaptureOptions& options) {
|
||||
options_ = options;
|
||||
bool ScreenCapturerLinux::Initialize() {
|
||||
helper_.SetLogGridSize(4);
|
||||
|
||||
root_window_ = RootWindow(display(), DefaultScreen(display()));
|
||||
if (root_window_ == BadValue) {
|
||||
@ -198,11 +194,6 @@ void ScreenCapturerLinux::InitXDamage() {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(lambroslambrou): Disable DAMAGE in situations where it is known
|
||||
// to fail, such as when Desktop Effects are enabled, with graphics
|
||||
// drivers (nVidia, ATI) that fail to report DAMAGE notifications
|
||||
// properly.
|
||||
|
||||
// Request notifications every time the screen becomes damaged.
|
||||
damage_handle_ = XDamageCreate(display(), root_window_,
|
||||
XDamageReportNonEmpty);
|
||||
@ -227,13 +218,20 @@ void ScreenCapturerLinux::InitXDamage() {
|
||||
}
|
||||
|
||||
void ScreenCapturerLinux::Start(Callback* callback) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(!callback_);
|
||||
RTC_DCHECK(callback);
|
||||
|
||||
callback_ = callback;
|
||||
|
||||
if (!Initialize()) {
|
||||
callback_->OnInitializationFailed();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenCapturerLinux::Capture(const DesktopRegion& region) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
|
||||
TickTime capture_start_time = TickTime::Now();
|
||||
|
||||
queue_.MoveToNextFrame();
|
||||
@ -279,7 +277,9 @@ void ScreenCapturerLinux::Capture(const DesktopRegion& region) {
|
||||
}
|
||||
|
||||
bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(screens->size() == 0);
|
||||
|
||||
// TODO(jiayl): implement screen enumeration.
|
||||
Screen default_screen;
|
||||
default_screen.id = 0;
|
||||
@ -288,11 +288,14 @@ bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) {
|
||||
}
|
||||
|
||||
bool ScreenCapturerLinux::SelectScreen(ScreenId id) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
// TODO(jiayl): implement screen selection.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScreenCapturerLinux::HandleXEvent(const XEvent& event) {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
|
||||
if (use_damage_ && (event.type == damage_event_base_ + XDamageNotify)) {
|
||||
const XDamageNotifyEvent* damage_event =
|
||||
reinterpret_cast<const XDamageNotifyEvent*>(&event);
|
||||
@ -309,7 +312,7 @@ bool ScreenCapturerLinux::HandleXEvent(const XEvent& event) {
|
||||
|
||||
DesktopFrame* ScreenCapturerLinux::CaptureScreen() {
|
||||
DesktopFrame* frame = queue_.current_frame()->Share();
|
||||
assert(x_server_pixel_buffer_.window_size().equals(frame->size()));
|
||||
RTC_DCHECK(x_server_pixel_buffer_.window_size().equals(frame->size()));
|
||||
|
||||
// Pass the screen size to the helper, so it can clip the invalid region if it
|
||||
// expands that region to a grid.
|
||||
@ -436,10 +439,7 @@ ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
|
||||
if (!options.x_display())
|
||||
return NULL;
|
||||
|
||||
std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
|
||||
if (!capturer->Init(options))
|
||||
capturer.reset();
|
||||
return capturer.release();
|
||||
return new ScreenCapturerLinux(options);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user