Use std::unique_ptr<> to pass frame ownership in DesktopCapturer impls.
Previously raw pointers were used for owned DesktopFrame instances. Updated all screen and window capturer implementations to use std::unique_ptr<>. Also includes some other cleanups in the capturers: - s/NULL/nullptr - moved default initializers to class definition. BUG=webrtc:5950 Review-Url: https://codereview.webrtc.org/1988783003 Cr-Commit-Position: refs/heads/master@{#13058}
This commit is contained in:
@ -19,7 +19,8 @@ namespace webrtc {
|
|||||||
// A DesktopFrame that is a sub-rect of another DesktopFrame.
|
// A DesktopFrame that is a sub-rect of another DesktopFrame.
|
||||||
class CroppedDesktopFrame : public DesktopFrame {
|
class CroppedDesktopFrame : public DesktopFrame {
|
||||||
public:
|
public:
|
||||||
CroppedDesktopFrame(DesktopFrame* frame, const DesktopRect& rect);
|
CroppedDesktopFrame(std::unique_ptr<DesktopFrame> frame,
|
||||||
|
const DesktopRect& rect);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<DesktopFrame> frame_;
|
std::unique_ptr<DesktopFrame> frame_;
|
||||||
@ -27,23 +28,23 @@ class CroppedDesktopFrame : public DesktopFrame {
|
|||||||
RTC_DISALLOW_COPY_AND_ASSIGN(CroppedDesktopFrame);
|
RTC_DISALLOW_COPY_AND_ASSIGN(CroppedDesktopFrame);
|
||||||
};
|
};
|
||||||
|
|
||||||
DesktopFrame*
|
std::unique_ptr<DesktopFrame> CreateCroppedDesktopFrame(
|
||||||
CreateCroppedDesktopFrame(DesktopFrame* frame, const DesktopRect& rect) {
|
std::unique_ptr<DesktopFrame> frame,
|
||||||
if (!DesktopRect::MakeSize(frame->size()).ContainsRect(rect)) {
|
const DesktopRect& rect) {
|
||||||
delete frame;
|
if (!DesktopRect::MakeSize(frame->size()).ContainsRect(rect))
|
||||||
return NULL;
|
return nullptr;
|
||||||
|
|
||||||
|
return std::unique_ptr<DesktopFrame>(
|
||||||
|
new CroppedDesktopFrame(std::move(frame), rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CroppedDesktopFrame(frame, rect);
|
CroppedDesktopFrame::CroppedDesktopFrame(std::unique_ptr<DesktopFrame> frame,
|
||||||
}
|
|
||||||
|
|
||||||
CroppedDesktopFrame::CroppedDesktopFrame(DesktopFrame* frame,
|
|
||||||
const DesktopRect& rect)
|
const DesktopRect& rect)
|
||||||
: DesktopFrame(rect.size(),
|
: DesktopFrame(rect.size(),
|
||||||
frame->stride(),
|
frame->stride(),
|
||||||
frame->GetFrameDataAtPos(rect.top_left()),
|
frame->GetFrameDataAtPos(rect.top_left()),
|
||||||
frame->shared_memory()),
|
frame->shared_memory()) {
|
||||||
frame_(frame) {
|
frame_ = std::move(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -15,10 +15,11 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
// Always takes ownership of |frame|. Returns NULL if |rect| is not contained
|
// Returns nullptr frame if |rect| is not contained by the bounds of |frame|.
|
||||||
// by the bounds of |frame|.
|
std::unique_ptr<DesktopFrame> CreateCroppedDesktopFrame(
|
||||||
DesktopFrame* CreateCroppedDesktopFrame(DesktopFrame* frame,
|
std::unique_ptr<DesktopFrame> frame,
|
||||||
const DesktopRect& rect);
|
const DesktopRect& rect);
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_CROPPED_DESKTOP_FRAME_H_
|
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_CROPPED_DESKTOP_FRAME_H_
|
||||||
|
|||||||
@ -74,31 +74,31 @@ bool CroppingWindowCapturer::BringSelectedWindowToFront() {
|
|||||||
return window_capturer_->BringSelectedWindowToFront();
|
return window_capturer_->BringSelectedWindowToFront();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CroppingWindowCapturer::OnCaptureCompleted(DesktopFrame* frame) {
|
void CroppingWindowCapturer::OnCaptureResult(
|
||||||
std::unique_ptr<DesktopFrame> screen_frame(frame);
|
DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame> screen_frame) {
|
||||||
if (!ShouldUseScreenCapturer()) {
|
if (!ShouldUseScreenCapturer()) {
|
||||||
LOG(LS_INFO) << "Window no longer on top when ScreenCapturer finishes";
|
LOG(LS_INFO) << "Window no longer on top when ScreenCapturer finishes";
|
||||||
window_capturer_->Capture(DesktopRegion());
|
window_capturer_->Capture(DesktopRegion());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!frame) {
|
if (result != Result::SUCCESS) {
|
||||||
LOG(LS_WARNING) << "ScreenCapturer failed to capture a frame";
|
LOG(LS_WARNING) << "ScreenCapturer failed to capture a frame";
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(result, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopRect window_rect = GetWindowRectInVirtualScreen();
|
DesktopRect window_rect = GetWindowRectInVirtualScreen();
|
||||||
if (window_rect.is_empty()) {
|
if (window_rect.is_empty()) {
|
||||||
LOG(LS_WARNING) << "Window rect is empty";
|
LOG(LS_WARNING) << "Window rect is empty";
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DesktopFrame> window_frame(
|
callback_->OnCaptureResult(
|
||||||
CreateCroppedDesktopFrame(screen_frame.release(), window_rect));
|
Result::SUCCESS,
|
||||||
callback_->OnCaptureCompleted(window_frame.release());
|
CreateCroppedDesktopFrame(std::move(screen_frame), window_rect));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(WEBRTC_WIN)
|
#if !defined(WEBRTC_WIN)
|
||||||
|
|||||||
@ -42,7 +42,8 @@ class CroppingWindowCapturer : public WindowCapturer,
|
|||||||
|
|
||||||
// DesktopCapturer::Callback implementation, passed to |screen_capturer_| to
|
// DesktopCapturer::Callback implementation, passed to |screen_capturer_| to
|
||||||
// intercept the capture result.
|
// intercept the capture result.
|
||||||
void OnCaptureCompleted(DesktopFrame* frame) override;
|
void OnCaptureResult(DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame> frame) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit CroppingWindowCapturer(const DesktopCaptureOptions& options);
|
explicit CroppingWindowCapturer(const DesktopCaptureOptions& options);
|
||||||
|
|||||||
@ -57,7 +57,7 @@ void AlphaBlend(uint8_t* dest, int dest_stride,
|
|||||||
class DesktopFrameWithCursor : public DesktopFrame {
|
class DesktopFrameWithCursor : public DesktopFrame {
|
||||||
public:
|
public:
|
||||||
// Takes ownership of |frame|.
|
// Takes ownership of |frame|.
|
||||||
DesktopFrameWithCursor(DesktopFrame* frame,
|
DesktopFrameWithCursor(std::unique_ptr<DesktopFrame> frame,
|
||||||
const MouseCursor& cursor,
|
const MouseCursor& cursor,
|
||||||
const DesktopVector& position);
|
const DesktopVector& position);
|
||||||
virtual ~DesktopFrameWithCursor();
|
virtual ~DesktopFrameWithCursor();
|
||||||
@ -71,15 +71,18 @@ class DesktopFrameWithCursor : public DesktopFrame {
|
|||||||
RTC_DISALLOW_COPY_AND_ASSIGN(DesktopFrameWithCursor);
|
RTC_DISALLOW_COPY_AND_ASSIGN(DesktopFrameWithCursor);
|
||||||
};
|
};
|
||||||
|
|
||||||
DesktopFrameWithCursor::DesktopFrameWithCursor(DesktopFrame* frame,
|
DesktopFrameWithCursor::DesktopFrameWithCursor(
|
||||||
|
std::unique_ptr<DesktopFrame> frame,
|
||||||
const MouseCursor& cursor,
|
const MouseCursor& cursor,
|
||||||
const DesktopVector& position)
|
const DesktopVector& position)
|
||||||
: DesktopFrame(frame->size(), frame->stride(),
|
: DesktopFrame(frame->size(),
|
||||||
frame->data(), frame->shared_memory()),
|
frame->stride(),
|
||||||
original_frame_(frame) {
|
frame->data(),
|
||||||
|
frame->shared_memory()) {
|
||||||
set_dpi(frame->dpi());
|
set_dpi(frame->dpi());
|
||||||
set_capture_time_ms(frame->capture_time_ms());
|
set_capture_time_ms(frame->capture_time_ms());
|
||||||
mutable_updated_region()->Swap(frame->mutable_updated_region());
|
mutable_updated_region()->Swap(frame->mutable_updated_region());
|
||||||
|
original_frame_ = std::move(frame);
|
||||||
|
|
||||||
DesktopVector image_pos = position.subtract(cursor.hotspot());
|
DesktopVector image_pos = position.subtract(cursor.hotspot());
|
||||||
DesktopRect target_rect = DesktopRect::MakeSize(cursor.image()->size());
|
DesktopRect target_rect = DesktopRect::MakeSize(cursor.image()->size());
|
||||||
@ -152,14 +155,15 @@ void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) {
|
|||||||
desktop_capturer_->SetExcludedWindow(window);
|
desktop_capturer_->SetExcludedWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopAndCursorComposer::OnCaptureCompleted(DesktopFrame* frame) {
|
void DesktopAndCursorComposer::OnCaptureResult(
|
||||||
if (frame && cursor_.get() && cursor_state_ == MouseCursorMonitor::INSIDE) {
|
DesktopCapturer::Result result,
|
||||||
DesktopFrameWithCursor* frame_with_cursor =
|
std::unique_ptr<DesktopFrame> frame) {
|
||||||
new DesktopFrameWithCursor(frame, *cursor_, cursor_position_);
|
if (frame && cursor_ && cursor_state_ == MouseCursorMonitor::INSIDE) {
|
||||||
frame = frame_with_cursor;
|
frame = std::unique_ptr<DesktopFrameWithCursor>(new DesktopFrameWithCursor(
|
||||||
|
std::move(frame), *cursor_, cursor_position_));
|
||||||
}
|
}
|
||||||
|
|
||||||
callback_->OnCaptureCompleted(frame);
|
callback_->OnCaptureResult(result, std::move(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) {
|
void DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) {
|
||||||
|
|||||||
@ -42,7 +42,8 @@ class DesktopAndCursorComposer : public DesktopCapturer,
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// DesktopCapturer::Callback interface.
|
// DesktopCapturer::Callback interface.
|
||||||
void OnCaptureCompleted(DesktopFrame* frame) override;
|
void OnCaptureResult(DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame> frame) override;
|
||||||
|
|
||||||
// MouseCursorMonitor::Callback interface.
|
// MouseCursorMonitor::Callback interface.
|
||||||
void OnMouseCursor(MouseCursor* cursor) override;
|
void OnMouseCursor(MouseCursor* cursor) override;
|
||||||
|
|||||||
@ -78,15 +78,17 @@ class FakeScreenCapturer : public DesktopCapturer {
|
|||||||
void Start(Callback* callback) override { callback_ = callback; }
|
void Start(Callback* callback) override { callback_ = callback; }
|
||||||
|
|
||||||
void Capture(const DesktopRegion& region) override {
|
void Capture(const DesktopRegion& region) override {
|
||||||
callback_->OnCaptureCompleted(next_frame_.release());
|
callback_->OnCaptureResult(
|
||||||
|
next_frame_ ? Result::SUCCESS : Result::ERROR_TEMPORARY,
|
||||||
|
std::move(next_frame_));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetNextFrame(DesktopFrame* next_frame) {
|
void SetNextFrame(std::unique_ptr<DesktopFrame> next_frame) {
|
||||||
next_frame_.reset(next_frame);
|
next_frame_ = std::move(next_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<DesktopFrame> next_frame_;
|
std::unique_ptr<DesktopFrame> next_frame_;
|
||||||
};
|
};
|
||||||
@ -165,11 +167,13 @@ class DesktopAndCursorComposerTest : public testing::Test,
|
|||||||
DesktopAndCursorComposerTest()
|
DesktopAndCursorComposerTest()
|
||||||
: fake_screen_(new FakeScreenCapturer()),
|
: fake_screen_(new FakeScreenCapturer()),
|
||||||
fake_cursor_(new FakeMouseMonitor()),
|
fake_cursor_(new FakeMouseMonitor()),
|
||||||
blender_(fake_screen_, fake_cursor_) {
|
blender_(fake_screen_, fake_cursor_) {}
|
||||||
}
|
|
||||||
|
|
||||||
// DesktopCapturer::Callback interface
|
// DesktopCapturer::Callback interface
|
||||||
void OnCaptureCompleted(DesktopFrame* frame) override { frame_.reset(frame); }
|
void OnCaptureResult(DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame> frame) override {
|
||||||
|
frame_ = std::move(frame);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Owned by |blender_|.
|
// Owned by |blender_|.
|
||||||
@ -187,7 +191,7 @@ TEST_F(DesktopAndCursorComposerTest, Error) {
|
|||||||
|
|
||||||
fake_cursor_->SetHotspot(DesktopVector());
|
fake_cursor_->SetHotspot(DesktopVector());
|
||||||
fake_cursor_->SetState(MouseCursorMonitor::INSIDE, DesktopVector());
|
fake_cursor_->SetState(MouseCursorMonitor::INSIDE, DesktopVector());
|
||||||
fake_screen_->SetNextFrame(NULL);
|
fake_screen_->SetNextFrame(nullptr);
|
||||||
|
|
||||||
blender_.Capture(DesktopRegion());
|
blender_.Capture(DesktopRegion());
|
||||||
|
|
||||||
|
|||||||
@ -15,24 +15,45 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||||
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
|
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
|
||||||
#include "webrtc/modules/desktop_capture/shared_memory.h"
|
#include "webrtc/modules/desktop_capture/shared_memory.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
class DesktopFrame;
|
class DesktopFrame;
|
||||||
class DesktopRegion;
|
|
||||||
|
|
||||||
// Abstract interface for screen and window capturers.
|
// Abstract interface for screen and window capturers.
|
||||||
class DesktopCapturer {
|
class DesktopCapturer {
|
||||||
public:
|
public:
|
||||||
|
enum class Result {
|
||||||
|
// The frame was captured successfully.
|
||||||
|
SUCCESS,
|
||||||
|
|
||||||
|
// There was a temporary error. The caller should continue calling
|
||||||
|
// Capture(), in the expectation that it will eventually recover.
|
||||||
|
ERROR_TEMPORARY,
|
||||||
|
|
||||||
|
// Capture has failed and will keep failing if the caller tries calling
|
||||||
|
// Capture() again.
|
||||||
|
ERROR_PERMANENT,
|
||||||
|
};
|
||||||
|
|
||||||
// Interface that must be implemented by the DesktopCapturer consumers.
|
// Interface that must be implemented by the DesktopCapturer consumers.
|
||||||
class Callback {
|
class Callback {
|
||||||
public:
|
public:
|
||||||
// Called after a frame has been captured. Handler must take ownership of
|
// Called after a frame has been captured. |frame| is not nullptr if and
|
||||||
// |frame|. If capture has failed for any reason |frame| is set to NULL
|
// only if |result| is SUCCESS.
|
||||||
// (e.g. the window has been closed).
|
virtual void OnCaptureResult(Result result,
|
||||||
virtual void OnCaptureCompleted(DesktopFrame* frame) = 0;
|
std::unique_ptr<DesktopFrame> frame) {
|
||||||
|
OnCaptureCompleted(frame.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated version of the method above that uses raw pointer instead of
|
||||||
|
// std::unique_ptr<>.
|
||||||
|
// TODO(sergeyu): Remove this method and make OnCaptureResult() pure
|
||||||
|
// virtual. crbug.com/webrtc/5950
|
||||||
|
virtual void OnCaptureCompleted(DesktopFrame* frame) { delete frame; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~Callback() {}
|
virtual ~Callback() {}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ DesktopFrameWin::~DesktopFrameWin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
DesktopFrameWin* DesktopFrameWin::Create(
|
std::unique_ptr<DesktopFrameWin> DesktopFrameWin::Create(
|
||||||
DesktopSize size,
|
DesktopSize size,
|
||||||
SharedMemoryFactory* shared_memory_factory,
|
SharedMemoryFactory* shared_memory_factory,
|
||||||
HDC hdc) {
|
HDC hdc) {
|
||||||
@ -60,9 +60,9 @@ DesktopFrameWin* DesktopFrameWin::Create(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DesktopFrameWin(size, bytes_per_row,
|
return std::unique_ptr<DesktopFrameWin>(
|
||||||
reinterpret_cast<uint8_t*>(data),
|
new DesktopFrameWin(size, bytes_per_row, reinterpret_cast<uint8_t*>(data),
|
||||||
std::move(shared_memory), bitmap);
|
std::move(shared_memory), bitmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -26,9 +26,9 @@ namespace webrtc {
|
|||||||
class DesktopFrameWin : public DesktopFrame {
|
class DesktopFrameWin : public DesktopFrame {
|
||||||
public:
|
public:
|
||||||
virtual ~DesktopFrameWin();
|
virtual ~DesktopFrameWin();
|
||||||
static DesktopFrameWin* Create(DesktopSize size,
|
|
||||||
SharedMemoryFactory* shared_memory_factory,
|
static std::unique_ptr<DesktopFrameWin>
|
||||||
HDC hdc);
|
Create(DesktopSize size, SharedMemoryFactory* shared_memory_factory, HDC hdc);
|
||||||
|
|
||||||
HBITMAP bitmap() { return bitmap_; }
|
HBITMAP bitmap() { return bitmap_; }
|
||||||
|
|
||||||
|
|||||||
@ -49,8 +49,8 @@ class ScreenCaptureFrameQueue {
|
|||||||
|
|
||||||
// Replaces the current frame with a new one allocated by the caller. The
|
// Replaces the current frame with a new one allocated by the caller. The
|
||||||
// existing frame (if any) is destroyed. Takes ownership of |frame|.
|
// existing frame (if any) is destroyed. Takes ownership of |frame|.
|
||||||
void ReplaceCurrentFrame(FrameType* frame) {
|
void ReplaceCurrentFrame(std::unique_ptr<FrameType> frame) {
|
||||||
frames_[current_].reset(frame);
|
frames_[current_] = std::move(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marks all frames obsolete and resets the previous frame pointer. No
|
// Marks all frames obsolete and resets the previous frame pointer. No
|
||||||
|
|||||||
@ -96,15 +96,15 @@ void CopyRect(const uint8_t* src_plane,
|
|||||||
// caller should release the returned CFArrayRef.
|
// caller should release the returned CFArrayRef.
|
||||||
CFArrayRef CreateWindowListWithExclusion(CGWindowID window_to_exclude) {
|
CFArrayRef CreateWindowListWithExclusion(CGWindowID window_to_exclude) {
|
||||||
if (!window_to_exclude)
|
if (!window_to_exclude)
|
||||||
return NULL;
|
return nullptr;
|
||||||
|
|
||||||
CFArrayRef all_windows = CGWindowListCopyWindowInfo(
|
CFArrayRef all_windows = CGWindowListCopyWindowInfo(
|
||||||
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||||
if (!all_windows)
|
if (!all_windows)
|
||||||
return NULL;
|
return nullptr;
|
||||||
|
|
||||||
CFMutableArrayRef returned_array = CFArrayCreateMutable(
|
CFMutableArrayRef returned_array =
|
||||||
NULL, CFArrayGetCount(all_windows), NULL);
|
CFArrayCreateMutable(nullptr, CFArrayGetCount(all_windows), nullptr);
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (CFIndex i = 0; i < CFArrayGetCount(all_windows); ++i) {
|
for (CFIndex i = 0; i < CFArrayGetCount(all_windows); ++i) {
|
||||||
@ -126,7 +126,7 @@ CFArrayRef CreateWindowListWithExclusion(CGWindowID window_to_exclude) {
|
|||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
CFRelease(returned_array);
|
CFRelease(returned_array);
|
||||||
returned_array = NULL;
|
returned_array = nullptr;
|
||||||
}
|
}
|
||||||
return returned_array;
|
return returned_array;
|
||||||
}
|
}
|
||||||
@ -143,7 +143,7 @@ DesktopRect GetExcludedWindowPixelBounds(CGWindowID window,
|
|||||||
ids[0] = window;
|
ids[0] = window;
|
||||||
|
|
||||||
CFArrayRef window_id_array =
|
CFArrayRef window_id_array =
|
||||||
CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
|
CFArrayCreate(nullptr, reinterpret_cast<const void**>(&ids), 1, nullptr);
|
||||||
CFArrayRef window_array =
|
CFArrayRef window_array =
|
||||||
CGWindowListCreateDescriptionFromArray(window_id_array);
|
CGWindowListCreateDescriptionFromArray(window_id_array);
|
||||||
|
|
||||||
@ -229,11 +229,11 @@ class ScreenCapturerMac : public ScreenCapturer {
|
|||||||
void *user_parameter);
|
void *user_parameter);
|
||||||
void ReleaseBuffers();
|
void ReleaseBuffers();
|
||||||
|
|
||||||
DesktopFrame* CreateFrame();
|
std::unique_ptr<DesktopFrame> CreateFrame();
|
||||||
|
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
|
|
||||||
CGLContextObj cgl_context_;
|
CGLContextObj cgl_context_ = nullptr;
|
||||||
ScopedPixelBufferObject pixel_buffer_object_;
|
ScopedPixelBufferObject pixel_buffer_object_;
|
||||||
|
|
||||||
// Queue of the frames buffers.
|
// Queue of the frames buffers.
|
||||||
@ -244,13 +244,13 @@ class ScreenCapturerMac : public ScreenCapturer {
|
|||||||
|
|
||||||
// Currently selected display, or 0 if the full desktop is selected. On OS X
|
// Currently selected display, or 0 if the full desktop is selected. On OS X
|
||||||
// 10.6 and before, this is always 0.
|
// 10.6 and before, this is always 0.
|
||||||
CGDirectDisplayID current_display_;
|
CGDirectDisplayID current_display_ = 0;
|
||||||
|
|
||||||
// The physical pixel bounds of the current screen.
|
// The physical pixel bounds of the current screen.
|
||||||
DesktopRect screen_pixel_bounds_;
|
DesktopRect screen_pixel_bounds_;
|
||||||
|
|
||||||
// The dip to physical pixel scale of the current screen.
|
// 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
|
// A thread-safe list of invalid rectangles, and the size of the most
|
||||||
// recently captured screen.
|
// recently captured screen.
|
||||||
@ -263,20 +263,20 @@ class ScreenCapturerMac : public ScreenCapturer {
|
|||||||
rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor_;
|
rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor_;
|
||||||
|
|
||||||
// Power management assertion to prevent the screen from sleeping.
|
// 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.
|
// 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.
|
// Dynamically link to deprecated APIs for Mac OS X 10.6 support.
|
||||||
void* app_services_library_;
|
void* app_services_library_ = nullptr;
|
||||||
CGDisplayBaseAddressFunc cg_display_base_address_;
|
CGDisplayBaseAddressFunc cg_display_base_address_ = nullptr;
|
||||||
CGDisplayBytesPerRowFunc cg_display_bytes_per_row_;
|
CGDisplayBytesPerRowFunc cg_display_bytes_per_row_ = nullptr;
|
||||||
CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_;
|
CGDisplayBitsPerPixelFunc cg_display_bits_per_pixel_ = nullptr;
|
||||||
void* opengl_library_;
|
void* opengl_library_ = nullptr;
|
||||||
CGLSetFullScreenFunc cgl_set_full_screen_;
|
CGLSetFullScreenFunc cgl_set_full_screen_ = nullptr;
|
||||||
|
|
||||||
CGWindowID excluded_window_;
|
CGWindowID excluded_window_ = 0;
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac);
|
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerMac);
|
||||||
};
|
};
|
||||||
@ -285,16 +285,16 @@ class ScreenCapturerMac : public ScreenCapturer {
|
|||||||
// stride.
|
// stride.
|
||||||
class InvertedDesktopFrame : public DesktopFrame {
|
class InvertedDesktopFrame : public DesktopFrame {
|
||||||
public:
|
public:
|
||||||
// Takes ownership of |frame|.
|
InvertedDesktopFrame(std::unique_ptr<DesktopFrame> frame)
|
||||||
InvertedDesktopFrame(DesktopFrame* frame)
|
|
||||||
: DesktopFrame(
|
: DesktopFrame(
|
||||||
frame->size(), -frame->stride(),
|
frame->size(),
|
||||||
|
-frame->stride(),
|
||||||
frame->data() + (frame->size().height() - 1) * frame->stride(),
|
frame->data() + (frame->size().height() - 1) * frame->stride(),
|
||||||
frame->shared_memory()),
|
frame->shared_memory()) {
|
||||||
original_frame_(frame) {
|
original_frame_ = std::move(frame);
|
||||||
set_dpi(frame->dpi());
|
set_dpi(original_frame_->dpi());
|
||||||
set_capture_time_ms(frame->capture_time_ms());
|
set_capture_time_ms(original_frame_->capture_time_ms());
|
||||||
mutable_updated_region()->Swap(frame->mutable_updated_region());
|
mutable_updated_region()->Swap(original_frame_->mutable_updated_region());
|
||||||
}
|
}
|
||||||
virtual ~InvertedDesktopFrame() {}
|
virtual ~InvertedDesktopFrame() {}
|
||||||
|
|
||||||
@ -306,21 +306,7 @@ class InvertedDesktopFrame : public DesktopFrame {
|
|||||||
|
|
||||||
ScreenCapturerMac::ScreenCapturerMac(
|
ScreenCapturerMac::ScreenCapturerMac(
|
||||||
rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor)
|
rtc::scoped_refptr<DesktopConfigurationMonitor> desktop_config_monitor)
|
||||||
: callback_(NULL),
|
: desktop_config_monitor_(desktop_config_monitor) {}
|
||||||
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) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreenCapturerMac::~ScreenCapturerMac() {
|
ScreenCapturerMac::~ScreenCapturerMac() {
|
||||||
if (power_assertion_id_display_ != kIOPMNullAssertionID) {
|
if (power_assertion_id_display_ != kIOPMNullAssertionID) {
|
||||||
@ -353,7 +339,7 @@ void ScreenCapturerMac::ReleaseBuffers() {
|
|||||||
if (cgl_context_) {
|
if (cgl_context_) {
|
||||||
pixel_buffer_object_.Release();
|
pixel_buffer_object_.Release();
|
||||||
CGLDestroyContext(cgl_context_);
|
CGLDestroyContext(cgl_context_);
|
||||||
cgl_context_ = NULL;
|
cgl_context_ = nullptr;
|
||||||
}
|
}
|
||||||
// The buffers might be in use by the encoder, so don't delete them here.
|
// The buffers might be in use by the encoder, so don't delete them here.
|
||||||
// Instead, mark them as "needs update"; next time the buffers are used by
|
// Instead, mark them as "needs update"; next time the buffers are used by
|
||||||
@ -419,7 +405,7 @@ void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) {
|
|||||||
// APIS currently crash on 10.6.8 if there is no monitor attached.
|
// APIS currently crash on 10.6.8 if there is no monitor attached.
|
||||||
if (!CgBlitPostLion(*current_frame, region)) {
|
if (!CgBlitPostLion(*current_frame, region)) {
|
||||||
desktop_config_monitor_->Unlock();
|
desktop_config_monitor_->Unlock();
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (cgl_context_) {
|
} else if (cgl_context_) {
|
||||||
@ -435,11 +421,11 @@ void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) {
|
|||||||
CgBlitPreLion(*current_frame, region);
|
CgBlitPreLion(*current_frame, region);
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopFrame* new_frame = queue_.current_frame()->Share();
|
std::unique_ptr<DesktopFrame> new_frame = queue_.current_frame()->Share();
|
||||||
*new_frame->mutable_updated_region() = region;
|
*new_frame->mutable_updated_region() = region;
|
||||||
|
|
||||||
if (flip)
|
if (flip)
|
||||||
new_frame = new InvertedDesktopFrame(new_frame);
|
new_frame.reset(new InvertedDesktopFrame(std::move(new_frame)));
|
||||||
|
|
||||||
helper_.set_size_most_recent(new_frame->size());
|
helper_.set_size_most_recent(new_frame->size());
|
||||||
|
|
||||||
@ -447,10 +433,9 @@ void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) {
|
|||||||
// and accessing display structures.
|
// and accessing display structures.
|
||||||
desktop_config_monitor_->Unlock();
|
desktop_config_monitor_->Unlock();
|
||||||
|
|
||||||
new_frame->set_capture_time_ms(
|
new_frame->set_capture_time_ms((rtc::TimeNanos() - capture_start_time_nanos) /
|
||||||
(rtc::TimeNanos() - capture_start_time_nanos) /
|
|
||||||
rtc::kNumNanosecsPerMillisec);
|
rtc::kNumNanosecsPerMillisec);
|
||||||
callback_->OnCaptureCompleted(new_frame);
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(new_frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenCapturerMac::SetExcludedWindow(WindowId window) {
|
void ScreenCapturerMac::SetExcludedWindow(WindowId window) {
|
||||||
@ -534,7 +519,7 @@ void ScreenCapturerMac::GlBlitFast(const DesktopFrame& frame,
|
|||||||
GL_UNSIGNED_BYTE, 0);
|
GL_UNSIGNED_BYTE, 0);
|
||||||
GLubyte* ptr = static_cast<GLubyte*>(
|
GLubyte* ptr = static_cast<GLubyte*>(
|
||||||
glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB));
|
glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB));
|
||||||
if (ptr == NULL) {
|
if (!ptr) {
|
||||||
// If the buffer can't be mapped, assume that it's no longer valid and
|
// If the buffer can't be mapped, assume that it's no longer valid and
|
||||||
// release it.
|
// release it.
|
||||||
pixel_buffer_object_.Release();
|
pixel_buffer_object_.Release();
|
||||||
@ -642,8 +627,7 @@ bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
|
|||||||
// TODO(wez): Get rid of this as per crbug.com/145064, or implement
|
// TODO(wez): Get rid of this as per crbug.com/145064, or implement
|
||||||
// crbug.com/92354.
|
// crbug.com/92354.
|
||||||
if (queue_.previous_frame()) {
|
if (queue_.previous_frame()) {
|
||||||
memcpy(frame.data(),
|
memcpy(frame.data(), queue_.previous_frame()->data(),
|
||||||
queue_.previous_frame()->data(),
|
|
||||||
frame.stride() * frame.size().height());
|
frame.stride() * frame.size().height());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,7 +676,7 @@ bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
|
|||||||
copy_region.Translate(-display_bounds.left(), -display_bounds.top());
|
copy_region.Translate(-display_bounds.left(), -display_bounds.top());
|
||||||
|
|
||||||
DesktopRect excluded_window_bounds;
|
DesktopRect excluded_window_bounds;
|
||||||
CGImageRef excluded_image = NULL;
|
CGImageRef excluded_image = nullptr;
|
||||||
if (excluded_window_ && window_list) {
|
if (excluded_window_ && window_list) {
|
||||||
// Get the region of the excluded window relative the primary display.
|
// Get the region of the excluded window relative the primary display.
|
||||||
excluded_window_bounds = GetExcludedWindowPixelBounds(
|
excluded_window_bounds = GetExcludedWindowPixelBounds(
|
||||||
@ -710,7 +694,7 @@ bool ScreenCapturerMac::CgBlitPostLion(const DesktopFrame& frame,
|
|||||||
|
|
||||||
// Create an image containing a snapshot of the display.
|
// Create an image containing a snapshot of the display.
|
||||||
CGImageRef image = CGDisplayCreateImage(display_config.id);
|
CGImageRef image = CGDisplayCreateImage(display_config.id);
|
||||||
if (image == NULL) {
|
if (!image) {
|
||||||
if (excluded_image)
|
if (excluded_image)
|
||||||
CFRelease(excluded_image);
|
CFRelease(excluded_image);
|
||||||
continue;
|
continue;
|
||||||
@ -874,13 +858,13 @@ void ScreenCapturerMac::ScreenConfigurationChanged() {
|
|||||||
(CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice),
|
(CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(mainDevice),
|
||||||
(CGLPixelFormatAttribute)0
|
(CGLPixelFormatAttribute)0
|
||||||
};
|
};
|
||||||
CGLPixelFormatObj pixel_format = NULL;
|
CGLPixelFormatObj pixel_format = nullptr;
|
||||||
GLint matching_pixel_format_count = 0;
|
GLint matching_pixel_format_count = 0;
|
||||||
CGLError err = CGLChoosePixelFormat(attributes,
|
CGLError err = CGLChoosePixelFormat(attributes,
|
||||||
&pixel_format,
|
&pixel_format,
|
||||||
&matching_pixel_format_count);
|
&matching_pixel_format_count);
|
||||||
assert(err == kCGLNoError);
|
assert(err == kCGLNoError);
|
||||||
err = CGLCreateContext(pixel_format, NULL, &cgl_context_);
|
err = CGLCreateContext(pixel_format, nullptr, &cgl_context_);
|
||||||
assert(err == kCGLNoError);
|
assert(err == kCGLNoError);
|
||||||
CGLDestroyPixelFormat(pixel_format);
|
CGLDestroyPixelFormat(pixel_format);
|
||||||
(*cgl_set_full_screen_)(cgl_context_);
|
(*cgl_set_full_screen_)(cgl_context_);
|
||||||
@ -969,13 +953,12 @@ void ScreenCapturerMac::ScreenUpdateMoveCallback(
|
|||||||
capturer->ScreenUpdateMove(delta, count, rect_array);
|
capturer->ScreenUpdateMove(delta, count, rect_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopFrame* ScreenCapturerMac::CreateFrame() {
|
std::unique_ptr<DesktopFrame> ScreenCapturerMac::CreateFrame() {
|
||||||
std::unique_ptr<DesktopFrame> frame(
|
std::unique_ptr<DesktopFrame> frame(
|
||||||
new BasicDesktopFrame(screen_pixel_bounds_.size()));
|
new BasicDesktopFrame(screen_pixel_bounds_.size()));
|
||||||
|
|
||||||
frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_,
|
frame->set_dpi(DesktopVector(kStandardDPI * dip_to_pixel_scale_,
|
||||||
kStandardDPI * dip_to_pixel_scale_));
|
kStandardDPI * dip_to_pixel_scale_));
|
||||||
return frame.release();
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -983,7 +966,7 @@ DesktopFrame* ScreenCapturerMac::CreateFrame() {
|
|||||||
// static
|
// static
|
||||||
ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
|
ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
|
||||||
if (!options.configuration_monitor())
|
if (!options.configuration_monitor())
|
||||||
return NULL;
|
return nullptr;
|
||||||
|
|
||||||
std::unique_ptr<ScreenCapturerMac> capturer(
|
std::unique_ptr<ScreenCapturerMac> capturer(
|
||||||
new ScreenCapturerMac(options.configuration_monitor()));
|
new ScreenCapturerMac(options.configuration_monitor()));
|
||||||
|
|||||||
@ -32,11 +32,13 @@ namespace webrtc {
|
|||||||
class ScreenCapturerMacTest : public testing::Test {
|
class ScreenCapturerMacTest : public testing::Test {
|
||||||
public:
|
public:
|
||||||
// Verifies that the whole screen is initially dirty.
|
// Verifies that the whole screen is initially dirty.
|
||||||
void CaptureDoneCallback1(DesktopFrame* frame);
|
void CaptureDoneCallback1(DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame>* frame);
|
||||||
|
|
||||||
// Verifies that a rectangle explicitly marked as dirty is propagated
|
// Verifies that a rectangle explicitly marked as dirty is propagated
|
||||||
// correctly.
|
// correctly.
|
||||||
void CaptureDoneCallback2(DesktopFrame* frame);
|
void CaptureDoneCallback2(DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame>* frame);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
@ -49,37 +51,40 @@ class ScreenCapturerMacTest : public testing::Test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void ScreenCapturerMacTest::CaptureDoneCallback1(
|
void ScreenCapturerMacTest::CaptureDoneCallback1(
|
||||||
DesktopFrame* frame) {
|
DesktopCapturer::Result result,
|
||||||
std::unique_ptr<DesktopFrame> owned_frame(frame);
|
std::unique_ptr<DesktopFrame>* frame) {
|
||||||
|
EXPECT_EQ(result, DesktopCapturer::Result::SUCCESS);
|
||||||
|
|
||||||
MacDesktopConfiguration config = MacDesktopConfiguration::GetCurrent(
|
MacDesktopConfiguration config = MacDesktopConfiguration::GetCurrent(
|
||||||
MacDesktopConfiguration::BottomLeftOrigin);
|
MacDesktopConfiguration::BottomLeftOrigin);
|
||||||
|
|
||||||
// Verify that the region contains full frame.
|
// Verify that the region contains full frame.
|
||||||
DesktopRegion::Iterator it(frame->updated_region());
|
DesktopRegion::Iterator it((*frame)->updated_region());
|
||||||
EXPECT_TRUE(!it.IsAtEnd() && it.rect().equals(config.pixel_bounds));
|
EXPECT_TRUE(!it.IsAtEnd() && it.rect().equals(config.pixel_bounds));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenCapturerMacTest::CaptureDoneCallback2(
|
void ScreenCapturerMacTest::CaptureDoneCallback2(
|
||||||
DesktopFrame* frame) {
|
DesktopCapturer::Result result,
|
||||||
std::unique_ptr<DesktopFrame> owned_frame(frame);
|
std::unique_ptr<DesktopFrame>* frame) {
|
||||||
|
EXPECT_EQ(result, DesktopCapturer::Result::SUCCESS);
|
||||||
|
|
||||||
MacDesktopConfiguration config = MacDesktopConfiguration::GetCurrent(
|
MacDesktopConfiguration config = MacDesktopConfiguration::GetCurrent(
|
||||||
MacDesktopConfiguration::BottomLeftOrigin);
|
MacDesktopConfiguration::BottomLeftOrigin);
|
||||||
int width = config.pixel_bounds.width();
|
int width = config.pixel_bounds.width();
|
||||||
int height = config.pixel_bounds.height();
|
int height = config.pixel_bounds.height();
|
||||||
|
|
||||||
EXPECT_EQ(width, frame->size().width());
|
EXPECT_EQ(width, (*frame)->size().width());
|
||||||
EXPECT_EQ(height, frame->size().height());
|
EXPECT_EQ(height, (*frame)->size().height());
|
||||||
EXPECT_TRUE(frame->data() != NULL);
|
EXPECT_TRUE((*frame)->data() != NULL);
|
||||||
// Depending on the capture method, the screen may be flipped or not, so
|
// Depending on the capture method, the screen may be flipped or not, so
|
||||||
// the stride may be positive or negative.
|
// the stride may be positive or negative.
|
||||||
EXPECT_EQ(static_cast<int>(sizeof(uint32_t) * width),
|
EXPECT_EQ(static_cast<int>(sizeof(uint32_t) * width),
|
||||||
abs(frame->stride()));
|
abs((*frame)->stride()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ScreenCapturerMacTest, Capture) {
|
TEST_F(ScreenCapturerMacTest, Capture) {
|
||||||
EXPECT_CALL(callback_, OnCaptureCompleted(_))
|
EXPECT_CALL(callback_,
|
||||||
|
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
|
||||||
.Times(2)
|
.Times(2)
|
||||||
.WillOnce(Invoke(this, &ScreenCapturerMacTest::CaptureDoneCallback1))
|
.WillOnce(Invoke(this, &ScreenCapturerMacTest::CaptureDoneCallback1))
|
||||||
.WillOnce(Invoke(this, &ScreenCapturerMacTest::CaptureDoneCallback2));
|
.WillOnce(Invoke(this, &ScreenCapturerMacTest::CaptureDoneCallback2));
|
||||||
|
|||||||
@ -36,7 +36,13 @@ class MockScreenCapturerCallback : public ScreenCapturer::Callback {
|
|||||||
MockScreenCapturerCallback() {}
|
MockScreenCapturerCallback() {}
|
||||||
virtual ~MockScreenCapturerCallback() {}
|
virtual ~MockScreenCapturerCallback() {}
|
||||||
|
|
||||||
MOCK_METHOD1(OnCaptureCompleted, void(DesktopFrame*));
|
MOCK_METHOD2(OnCaptureResultPtr,
|
||||||
|
void(DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame>* frame));
|
||||||
|
void OnCaptureResult(DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame> frame) override {
|
||||||
|
OnCaptureResultPtr(result, &frame);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(MockScreenCapturerCallback);
|
RTC_DISALLOW_COPY_AND_ASSIGN(MockScreenCapturerCallback);
|
||||||
|
|||||||
@ -23,7 +23,6 @@
|
|||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
using ::testing::AnyNumber;
|
using ::testing::AnyNumber;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
using ::testing::SaveArg;
|
|
||||||
|
|
||||||
const int kTestSharedMemoryId = 123;
|
const int kTestSharedMemoryId = 123;
|
||||||
|
|
||||||
@ -69,6 +68,10 @@ class FakeSharedMemoryFactory : public SharedMemoryFactory {
|
|||||||
RTC_DISALLOW_COPY_AND_ASSIGN(FakeSharedMemoryFactory);
|
RTC_DISALLOW_COPY_AND_ASSIGN(FakeSharedMemoryFactory);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ACTION_P(SaveUniquePtrArg, dest) {
|
||||||
|
*dest = std::move(*arg1);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ScreenCapturerTest, GetScreenListAndSelectScreen) {
|
TEST_F(ScreenCapturerTest, GetScreenListAndSelectScreen) {
|
||||||
webrtc::ScreenCapturer::ScreenList screens;
|
webrtc::ScreenCapturer::ScreenList screens;
|
||||||
EXPECT_TRUE(capturer_->GetScreenList(&screens));
|
EXPECT_TRUE(capturer_->GetScreenList(&screens));
|
||||||
@ -84,9 +87,10 @@ TEST_F(ScreenCapturerTest, StartCapturer) {
|
|||||||
|
|
||||||
TEST_F(ScreenCapturerTest, Capture) {
|
TEST_F(ScreenCapturerTest, Capture) {
|
||||||
// Assume that Start() treats the screen as invalid initially.
|
// Assume that Start() treats the screen as invalid initially.
|
||||||
DesktopFrame* frame = NULL;
|
std::unique_ptr<DesktopFrame> frame;
|
||||||
EXPECT_CALL(callback_, OnCaptureCompleted(_))
|
EXPECT_CALL(callback_,
|
||||||
.WillOnce(SaveArg<0>(&frame));
|
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
|
||||||
|
.WillOnce(SaveUniquePtrArg(&frame));
|
||||||
|
|
||||||
capturer_->Start(&callback_);
|
capturer_->Start(&callback_);
|
||||||
capturer_->Capture(DesktopRegion());
|
capturer_->Capture(DesktopRegion());
|
||||||
@ -105,16 +109,15 @@ TEST_F(ScreenCapturerTest, Capture) {
|
|||||||
EXPECT_TRUE(it.rect().equals(DesktopRect::MakeSize(frame->size())));
|
EXPECT_TRUE(it.rect().equals(DesktopRect::MakeSize(frame->size())));
|
||||||
it.Advance();
|
it.Advance();
|
||||||
EXPECT_TRUE(it.IsAtEnd());
|
EXPECT_TRUE(it.IsAtEnd());
|
||||||
|
|
||||||
delete frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
#if defined(WEBRTC_WIN)
|
||||||
|
|
||||||
TEST_F(ScreenCapturerTest, UseSharedBuffers) {
|
TEST_F(ScreenCapturerTest, UseSharedBuffers) {
|
||||||
DesktopFrame* frame = NULL;
|
std::unique_ptr<DesktopFrame> frame;
|
||||||
EXPECT_CALL(callback_, OnCaptureCompleted(_))
|
EXPECT_CALL(callback_,
|
||||||
.WillOnce(SaveArg<0>(&frame));
|
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
|
||||||
|
.WillOnce(SaveUniquePtrArg(&frame));
|
||||||
|
|
||||||
capturer_->Start(&callback_);
|
capturer_->Start(&callback_);
|
||||||
capturer_->SetSharedMemoryFactory(
|
capturer_->SetSharedMemoryFactory(
|
||||||
@ -124,8 +127,6 @@ TEST_F(ScreenCapturerTest, UseSharedBuffers) {
|
|||||||
ASSERT_TRUE(frame);
|
ASSERT_TRUE(frame);
|
||||||
ASSERT_TRUE(frame->shared_memory());
|
ASSERT_TRUE(frame->shared_memory());
|
||||||
EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId);
|
EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId);
|
||||||
|
|
||||||
delete frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ScreenCapturerTest, UseMagnifier) {
|
TEST_F(ScreenCapturerTest, UseMagnifier) {
|
||||||
@ -133,13 +134,14 @@ TEST_F(ScreenCapturerTest, UseMagnifier) {
|
|||||||
options.set_allow_use_magnification_api(true);
|
options.set_allow_use_magnification_api(true);
|
||||||
capturer_.reset(ScreenCapturer::Create(options));
|
capturer_.reset(ScreenCapturer::Create(options));
|
||||||
|
|
||||||
DesktopFrame* frame = NULL;
|
std::unique_ptr<DesktopFrame> frame;
|
||||||
EXPECT_CALL(callback_, OnCaptureCompleted(_)).WillOnce(SaveArg<0>(&frame));
|
EXPECT_CALL(callback_,
|
||||||
|
OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _))
|
||||||
|
.WillOnce(SaveUniquePtrArg(&frame));
|
||||||
|
|
||||||
capturer_->Start(&callback_);
|
capturer_->Start(&callback_);
|
||||||
capturer_->Capture(DesktopRegion());
|
capturer_->Capture(DesktopRegion());
|
||||||
ASSERT_TRUE(frame);
|
ASSERT_TRUE(frame);
|
||||||
delete frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // defined(WEBRTC_WIN)
|
#endif // defined(WEBRTC_WIN)
|
||||||
|
|||||||
@ -66,7 +66,7 @@ class ScreenCapturerLinux : public ScreenCapturer,
|
|||||||
// from HandleXEvent(). In the non-DAMAGE case, this captures the
|
// from HandleXEvent(). In the non-DAMAGE case, this captures the
|
||||||
// whole screen, then calculates some invalid rectangles that include any
|
// whole screen, then calculates some invalid rectangles that include any
|
||||||
// differences between this and the previous capture.
|
// differences between this and the previous capture.
|
||||||
DesktopFrame* CaptureScreen();
|
std::unique_ptr<DesktopFrame> CaptureScreen();
|
||||||
|
|
||||||
// Called when the screen configuration is changed.
|
// Called when the screen configuration is changed.
|
||||||
void ScreenConfigurationChanged();
|
void ScreenConfigurationChanged();
|
||||||
@ -82,23 +82,23 @@ class ScreenCapturerLinux : public ScreenCapturer,
|
|||||||
|
|
||||||
DesktopCaptureOptions options_;
|
DesktopCaptureOptions options_;
|
||||||
|
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
|
|
||||||
// X11 graphics context.
|
// X11 graphics context.
|
||||||
GC gc_;
|
GC gc_ = nullptr;
|
||||||
Window root_window_;
|
Window root_window_ = BadValue;
|
||||||
|
|
||||||
// XFixes.
|
// XFixes.
|
||||||
bool has_xfixes_;
|
bool has_xfixes_ = false;
|
||||||
int xfixes_event_base_;
|
int xfixes_event_base_ = -1;
|
||||||
int xfixes_error_base_;
|
int xfixes_error_base_ = -1;
|
||||||
|
|
||||||
// XDamage information.
|
// XDamage information.
|
||||||
bool use_damage_;
|
bool use_damage_ = false;
|
||||||
Damage damage_handle_;
|
Damage damage_handle_ = 0;
|
||||||
int damage_event_base_;
|
int damage_event_base_ = -1;
|
||||||
int damage_error_base_;
|
int damage_error_base_ = -1;
|
||||||
XserverRegion damage_region_;
|
XserverRegion damage_region_ = 0;
|
||||||
|
|
||||||
// Access to the X Server's pixel buffer.
|
// Access to the X Server's pixel buffer.
|
||||||
XServerPixelBuffer x_server_pixel_buffer_;
|
XServerPixelBuffer x_server_pixel_buffer_;
|
||||||
@ -120,18 +120,7 @@ class ScreenCapturerLinux : public ScreenCapturer,
|
|||||||
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
|
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
|
||||||
};
|
};
|
||||||
|
|
||||||
ScreenCapturerLinux::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);
|
helper_.SetLogGridSize(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,7 +238,7 @@ void ScreenCapturerLinux::Capture(const DesktopRegion& region) {
|
|||||||
// in a good shape.
|
// in a good shape.
|
||||||
if (!x_server_pixel_buffer_.is_initialized()) {
|
if (!x_server_pixel_buffer_.is_initialized()) {
|
||||||
// We failed to initialize pixel buffer.
|
// We failed to initialize pixel buffer.
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,29 +246,26 @@ void ScreenCapturerLinux::Capture(const DesktopRegion& region) {
|
|||||||
// Note that we can't reallocate other buffers at this point, since the caller
|
// Note that we can't reallocate other buffers at this point, since the caller
|
||||||
// may still be reading from them.
|
// may still be reading from them.
|
||||||
if (!queue_.current_frame()) {
|
if (!queue_.current_frame()) {
|
||||||
std::unique_ptr<DesktopFrame> frame(
|
queue_.ReplaceCurrentFrame(
|
||||||
new BasicDesktopFrame(x_server_pixel_buffer_.window_size()));
|
SharedDesktopFrame::Wrap(std::unique_ptr<DesktopFrame>(
|
||||||
queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(frame.release()));
|
new BasicDesktopFrame(x_server_pixel_buffer_.window_size()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the Differ helper used by CaptureFrame(), if needed.
|
// Refresh the Differ helper used by CaptureFrame(), if needed.
|
||||||
DesktopFrame* frame = queue_.current_frame();
|
DesktopFrame* frame = queue_.current_frame();
|
||||||
if (!use_damage_ && (
|
if (!use_damage_ &&
|
||||||
!differ_.get() ||
|
(!differ_ || (differ_->width() != frame->size().width()) ||
|
||||||
(differ_->width() != frame->size().width()) ||
|
|
||||||
(differ_->height() != frame->size().height()) ||
|
(differ_->height() != frame->size().height()) ||
|
||||||
(differ_->bytes_per_row() != frame->stride()))) {
|
(differ_->bytes_per_row() != frame->stride()))) {
|
||||||
differ_.reset(new Differ(frame->size().width(), frame->size().height(),
|
differ_.reset(new Differ(frame->size().width(), frame->size().height(),
|
||||||
DesktopFrame::kBytesPerPixel,
|
DesktopFrame::kBytesPerPixel, frame->stride()));
|
||||||
frame->stride()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopFrame* result = CaptureScreen();
|
std::unique_ptr<DesktopFrame> result = CaptureScreen();
|
||||||
last_invalid_region_ = result->updated_region();
|
last_invalid_region_ = result->updated_region();
|
||||||
result->set_capture_time_ms(
|
result->set_capture_time_ms((rtc::TimeNanos() - capture_start_time_nanos) /
|
||||||
(rtc::TimeNanos() - capture_start_time_nanos) /
|
|
||||||
rtc::kNumNanosecsPerMillisec);
|
rtc::kNumNanosecsPerMillisec);
|
||||||
callback_->OnCaptureCompleted(result);
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) {
|
bool ScreenCapturerLinux::GetScreenList(ScreenList* screens) {
|
||||||
@ -311,8 +297,8 @@ bool ScreenCapturerLinux::HandleXEvent(const XEvent& event) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopFrame* ScreenCapturerLinux::CaptureScreen() {
|
std::unique_ptr<DesktopFrame> ScreenCapturerLinux::CaptureScreen() {
|
||||||
DesktopFrame* frame = queue_.current_frame()->Share();
|
std::unique_ptr<SharedDesktopFrame> frame = queue_.current_frame()->Share();
|
||||||
assert(x_server_pixel_buffer_.window_size().equals(frame->size()));
|
assert(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
|
// Pass the screen size to the helper, so it can clip the invalid region if it
|
||||||
@ -354,18 +340,18 @@ DesktopFrame* ScreenCapturerLinux::CaptureScreen() {
|
|||||||
|
|
||||||
for (DesktopRegion::Iterator it(*updated_region);
|
for (DesktopRegion::Iterator it(*updated_region);
|
||||||
!it.IsAtEnd(); it.Advance()) {
|
!it.IsAtEnd(); it.Advance()) {
|
||||||
x_server_pixel_buffer_.CaptureRect(it.rect(), frame);
|
x_server_pixel_buffer_.CaptureRect(it.rect(), frame.get());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Doing full-screen polling, or this is the first capture after a
|
// Doing full-screen polling, or this is the first capture after a
|
||||||
// screen-resolution change. In either case, need a full-screen capture.
|
// screen-resolution change. In either case, need a full-screen capture.
|
||||||
DesktopRect screen_rect = DesktopRect::MakeSize(frame->size());
|
DesktopRect screen_rect = DesktopRect::MakeSize(frame->size());
|
||||||
x_server_pixel_buffer_.CaptureRect(screen_rect, frame);
|
x_server_pixel_buffer_.CaptureRect(screen_rect, frame.get());
|
||||||
|
|
||||||
if (queue_.previous_frame()) {
|
if (queue_.previous_frame()) {
|
||||||
// Full-screen polling, so calculate the invalid rects here, based on the
|
// Full-screen polling, so calculate the invalid rects here, based on the
|
||||||
// changed pixels between current and previous buffers.
|
// changed pixels between current and previous buffers.
|
||||||
RTC_DCHECK(differ_.get() != NULL);
|
RTC_DCHECK(differ_);
|
||||||
RTC_DCHECK(queue_.previous_frame()->data());
|
RTC_DCHECK(queue_.previous_frame()->data());
|
||||||
differ_->CalcDirtyRegion(queue_.previous_frame()->data(),
|
differ_->CalcDirtyRegion(queue_.previous_frame()->data(),
|
||||||
frame->data(), updated_region);
|
frame->data(), updated_region);
|
||||||
@ -378,7 +364,7 @@ DesktopFrame* ScreenCapturerLinux::CaptureScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return frame;
|
return std::move(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenCapturerLinux::ScreenConfigurationChanged() {
|
void ScreenCapturerLinux::ScreenConfigurationChanged() {
|
||||||
@ -415,7 +401,7 @@ void ScreenCapturerLinux::SynchronizeFrame() {
|
|||||||
void ScreenCapturerLinux::DeinitXlib() {
|
void ScreenCapturerLinux::DeinitXlib() {
|
||||||
if (gc_) {
|
if (gc_) {
|
||||||
XFreeGC(display(), gc_);
|
XFreeGC(display(), gc_);
|
||||||
gc_ = NULL;
|
gc_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
x_server_pixel_buffer_.Release();
|
x_server_pixel_buffer_.Release();
|
||||||
@ -438,7 +424,7 @@ void ScreenCapturerLinux::DeinitXlib() {
|
|||||||
// static
|
// static
|
||||||
ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
|
ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
|
||||||
if (!options.x_display())
|
if (!options.x_display())
|
||||||
return NULL;
|
return nullptr;
|
||||||
|
|
||||||
std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
|
std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
|
||||||
if (!capturer->Init(options))
|
if (!capturer->Init(options))
|
||||||
|
|||||||
@ -17,49 +17,25 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
class SharedDesktopFrame::Core {
|
|
||||||
public:
|
|
||||||
Core(DesktopFrame* frame) : frame_(frame) {}
|
|
||||||
|
|
||||||
DesktopFrame* frame() { return frame_.get(); }
|
|
||||||
|
|
||||||
bool HasOneRef() { return ref_count_.Value() == 1; }
|
|
||||||
|
|
||||||
virtual int32_t AddRef() {
|
|
||||||
return ++ref_count_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int32_t Release() {
|
|
||||||
int32_t ref_count;
|
|
||||||
ref_count = --ref_count_;
|
|
||||||
if (ref_count == 0)
|
|
||||||
delete this;
|
|
||||||
return ref_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual ~Core() {}
|
|
||||||
|
|
||||||
Atomic32 ref_count_;
|
|
||||||
std::unique_ptr<DesktopFrame> frame_;
|
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(Core);
|
|
||||||
};
|
|
||||||
|
|
||||||
SharedDesktopFrame::~SharedDesktopFrame() {}
|
SharedDesktopFrame::~SharedDesktopFrame() {}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
|
std::unique_ptr<SharedDesktopFrame> SharedDesktopFrame::Wrap(
|
||||||
|
std::unique_ptr<DesktopFrame> desktop_frame) {
|
||||||
|
return std::unique_ptr<SharedDesktopFrame>(
|
||||||
|
new SharedDesktopFrame(new Core(desktop_frame.release())));
|
||||||
|
}
|
||||||
|
|
||||||
SharedDesktopFrame* SharedDesktopFrame::Wrap(DesktopFrame* desktop_frame) {
|
SharedDesktopFrame* SharedDesktopFrame::Wrap(DesktopFrame* desktop_frame) {
|
||||||
rtc::scoped_refptr<Core> core(new Core(desktop_frame));
|
return Wrap(std::unique_ptr<DesktopFrame>(desktop_frame)).release();
|
||||||
return new SharedDesktopFrame(core);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopFrame* SharedDesktopFrame::GetUnderlyingFrame() {
|
DesktopFrame* SharedDesktopFrame::GetUnderlyingFrame() {
|
||||||
return core_->frame();
|
return core_->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedDesktopFrame* SharedDesktopFrame::Share() {
|
std::unique_ptr<SharedDesktopFrame> SharedDesktopFrame::Share() {
|
||||||
SharedDesktopFrame* result = new SharedDesktopFrame(core_);
|
std::unique_ptr<SharedDesktopFrame> result(new SharedDesktopFrame(core_));
|
||||||
result->set_dpi(dpi());
|
result->set_dpi(dpi());
|
||||||
result->set_capture_time_ms(capture_time_ms());
|
result->set_capture_time_ms(capture_time_ms());
|
||||||
*result->mutable_updated_region() = updated_region();
|
*result->mutable_updated_region() = updated_region();
|
||||||
@ -71,11 +47,10 @@ bool SharedDesktopFrame::IsShared() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SharedDesktopFrame::SharedDesktopFrame(rtc::scoped_refptr<Core> core)
|
SharedDesktopFrame::SharedDesktopFrame(rtc::scoped_refptr<Core> core)
|
||||||
: DesktopFrame(core->frame()->size(),
|
: DesktopFrame((*core)->size(),
|
||||||
core->frame()->stride(),
|
(*core)->stride(),
|
||||||
core->frame()->data(),
|
(*core)->data(),
|
||||||
core->frame()->shared_memory()),
|
(*core)->shared_memory()),
|
||||||
core_(core) {
|
core_(core) {}
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_SHARED_DESKTOP_FRAME_H_
|
#define WEBRTC_MODULES_DESKTOP_CAPTURE_SHARED_DESKTOP_FRAME_H_
|
||||||
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
#include "webrtc/base/constructormagic.h"
|
||||||
|
#include "webrtc/base/refcount.h"
|
||||||
#include "webrtc/base/scoped_ref_ptr.h"
|
#include "webrtc/base/scoped_ref_ptr.h"
|
||||||
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
#include "webrtc/modules/desktop_capture/desktop_frame.h"
|
||||||
|
|
||||||
@ -23,20 +24,25 @@ class SharedDesktopFrame : public DesktopFrame {
|
|||||||
public:
|
public:
|
||||||
virtual ~SharedDesktopFrame();
|
virtual ~SharedDesktopFrame();
|
||||||
|
|
||||||
|
static std::unique_ptr<SharedDesktopFrame> Wrap(
|
||||||
|
std::unique_ptr<DesktopFrame> desktop_frame);
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
// TODO(sergeyu): remove this method.
|
||||||
static SharedDesktopFrame* Wrap(DesktopFrame* desktop_frame);
|
static SharedDesktopFrame* Wrap(DesktopFrame* desktop_frame);
|
||||||
|
|
||||||
// Returns the underlying instance of DesktopFrame.
|
// Returns the underlying instance of DesktopFrame.
|
||||||
DesktopFrame* GetUnderlyingFrame();
|
DesktopFrame* GetUnderlyingFrame();
|
||||||
|
|
||||||
// Creates a clone of this object.
|
// Creates a clone of this object.
|
||||||
SharedDesktopFrame* Share();
|
std::unique_ptr<SharedDesktopFrame> Share();
|
||||||
|
|
||||||
// Checks if the frame is currently shared. If it returns false it's
|
// Checks if the frame is currently shared. If it returns false it's
|
||||||
// guaranteed that there are no clones of the object.
|
// guaranteed that there are no clones of the object.
|
||||||
bool IsShared();
|
bool IsShared();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Core;
|
typedef rtc::RefCountedObject<std::unique_ptr<DesktopFrame>> Core;
|
||||||
|
|
||||||
SharedDesktopFrame(rtc::scoped_refptr<Core> core);
|
SharedDesktopFrame(rtc::scoped_refptr<Core> core);
|
||||||
|
|
||||||
|
|||||||
@ -413,7 +413,14 @@ bool ScreenCapturerWinDirectx::DuplicateOutput() {
|
|||||||
_com_error error = g_container->output1->DuplicateOutput(
|
_com_error error = g_container->output1->DuplicateOutput(
|
||||||
static_cast<IUnknown*>(g_container->device),
|
static_cast<IUnknown*>(g_container->device),
|
||||||
g_container->duplication.GetAddressOf());
|
g_container->duplication.GetAddressOf());
|
||||||
if (error.Error() == S_OK && g_container->duplication) {
|
if (error.Error() != S_OK || !g_container->duplication) {
|
||||||
|
g_container->duplication.Reset();
|
||||||
|
LOG(LS_WARNING) << "Failed to duplicate output from IDXGIOutput1, error "
|
||||||
|
<< error.ErrorMessage() << ", with code "
|
||||||
|
<< error.Error();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&g_container->duplication_desc, 0, sizeof(DXGI_OUTDUPL_DESC));
|
memset(&g_container->duplication_desc, 0, sizeof(DXGI_OUTDUPL_DESC));
|
||||||
g_container->duplication->GetDesc(&g_container->duplication_desc);
|
g_container->duplication->GetDesc(&g_container->duplication_desc);
|
||||||
if (g_container->duplication_desc.ModeDesc.Format !=
|
if (g_container->duplication_desc.ModeDesc.Format !=
|
||||||
@ -425,16 +432,8 @@ bool ScreenCapturerWinDirectx::DuplicateOutput() {
|
|||||||
<< g_container->duplication_desc.ModeDesc.Format;
|
<< g_container->duplication_desc.ModeDesc.Format;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// Make sure we have correct signal and duplicate the output next time.
|
|
||||||
g_container->duplication.Reset();
|
|
||||||
LOG(LS_WARNING) << "Failed to duplicate output from IDXGIOutput1, error "
|
|
||||||
<< error.ErrorMessage() << ", with code "
|
|
||||||
<< error.Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScreenCapturerWinDirectx::ForceDuplicateOutput() {
|
bool ScreenCapturerWinDirectx::ForceDuplicateOutput() {
|
||||||
@ -458,8 +457,8 @@ ScreenCapturerWinDirectx::ScreenCapturerWinDirectx(
|
|||||||
|
|
||||||
// Texture instance won't change forever.
|
// Texture instance won't change forever.
|
||||||
while (!surfaces_.current_frame()) {
|
while (!surfaces_.current_frame()) {
|
||||||
surfaces_.ReplaceCurrentFrame(
|
surfaces_.ReplaceCurrentFrame(std::unique_ptr<rtc::scoped_refptr<Texture>>(
|
||||||
new rtc::scoped_refptr<Texture>(new Texture()));
|
new rtc::scoped_refptr<Texture>(new Texture())));
|
||||||
surfaces_.MoveToNextFrame();
|
surfaces_.MoveToNextFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,9 +592,9 @@ std::unique_ptr<DesktopFrame> ScreenCapturerWinDirectx::ProcessFrame(
|
|||||||
return std::unique_ptr<DesktopFrame>();
|
return std::unique_ptr<DesktopFrame>();
|
||||||
}
|
}
|
||||||
frames_.ReplaceCurrentFrame(
|
frames_.ReplaceCurrentFrame(
|
||||||
SharedDesktopFrame::Wrap(new_frame.release()));
|
SharedDesktopFrame::Wrap(std::move(new_frame)));
|
||||||
}
|
}
|
||||||
result.reset(frames_.current_frame()->Share());
|
result = frames_.current_frame()->Share();
|
||||||
|
|
||||||
std::unique_ptr<DesktopFrame> frame(
|
std::unique_ptr<DesktopFrame> frame(
|
||||||
new DxgiDesktopFrame(*surfaces_.current_frame()));
|
new DxgiDesktopFrame(*surfaces_.current_frame()));
|
||||||
@ -620,9 +619,8 @@ void ScreenCapturerWinDirectx::Capture(const DesktopRegion& region) {
|
|||||||
RTC_DCHECK(callback_);
|
RTC_DCHECK(callback_);
|
||||||
|
|
||||||
if (!g_container->duplication && !DuplicateOutput()) {
|
if (!g_container->duplication && !DuplicateOutput()) {
|
||||||
// Receive a capture request when application is shutting down, or between
|
// Failed to initialize desktop duplication.
|
||||||
// mode change.
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
callback_->OnCaptureCompleted(nullptr);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,7 +654,7 @@ void ScreenCapturerWinDirectx::Capture(const DesktopRegion& region) {
|
|||||||
if (ForceDuplicateOutput()) {
|
if (ForceDuplicateOutput()) {
|
||||||
EmitCurrentFrame();
|
EmitCurrentFrame();
|
||||||
} else {
|
} else {
|
||||||
callback_->OnCaptureCompleted(nullptr);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -677,14 +675,14 @@ void ScreenCapturerWinDirectx::Capture(const DesktopRegion& region) {
|
|||||||
g_container->duplication->ReleaseFrame();
|
g_container->duplication->ReleaseFrame();
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
callback_->OnCaptureCompleted(nullptr);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
result->set_capture_time_ms(
|
result->set_capture_time_ms(
|
||||||
(rtc::TimeNanos() - capture_start_time_nanos) /
|
(rtc::TimeNanos() - capture_start_time_nanos) /
|
||||||
rtc::kNumNanosecsPerMillisec);
|
rtc::kNumNanosecsPerMillisec);
|
||||||
callback_->OnCaptureCompleted(result.release());
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScreenCapturerWinDirectx::GetScreenList(ScreenList* screens) {
|
bool ScreenCapturerWinDirectx::GetScreenList(ScreenList* screens) {
|
||||||
@ -699,7 +697,7 @@ bool ScreenCapturerWinDirectx::SelectScreen(ScreenId id) {
|
|||||||
void ScreenCapturerWinDirectx::EmitCurrentFrame() {
|
void ScreenCapturerWinDirectx::EmitCurrentFrame() {
|
||||||
if (!surfaces_.current_frame()->get()->bits()) {
|
if (!surfaces_.current_frame()->get()->bits()) {
|
||||||
// At the very begining, we have not captured any frames.
|
// At the very begining, we have not captured any frames.
|
||||||
callback_->OnCaptureCompleted(nullptr);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,12 +706,12 @@ void ScreenCapturerWinDirectx::EmitCurrentFrame() {
|
|||||||
// queue. If there is not an existing frame (at the very begining), we can
|
// queue. If there is not an existing frame (at the very begining), we can
|
||||||
// only return a nullptr.
|
// only return a nullptr.
|
||||||
if (frames_.current_frame()) {
|
if (frames_.current_frame()) {
|
||||||
std::unique_ptr<SharedDesktopFrame> frame(
|
std::unique_ptr<SharedDesktopFrame> frame =
|
||||||
frames_.current_frame()->Share());
|
frames_.current_frame()->Share();
|
||||||
frame->mutable_updated_region()->Clear();
|
frame->mutable_updated_region()->Clear();
|
||||||
callback_->OnCaptureCompleted(frame.release());
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
||||||
} else {
|
} else {
|
||||||
callback_->OnCaptureCompleted(nullptr);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -722,7 +720,7 @@ void ScreenCapturerWinDirectx::EmitCurrentFrame() {
|
|||||||
// queue.
|
// queue.
|
||||||
std::unique_ptr<DesktopFrame> frame(
|
std::unique_ptr<DesktopFrame> frame(
|
||||||
new DxgiDesktopFrame(*surfaces_.current_frame()));
|
new DxgiDesktopFrame(*surfaces_.current_frame()));
|
||||||
callback_->OnCaptureCompleted(frame.release());
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -82,9 +82,7 @@ class ScreenCapturerWinDirectx : public ScreenCapturer {
|
|||||||
const char* stage);
|
const char* stage);
|
||||||
|
|
||||||
// Processes one frame received from AcquireNextFrame function, returns a
|
// Processes one frame received from AcquireNextFrame function, returns a
|
||||||
// nullptr if anything wrong, and Capture function will call
|
// nullptr if anything wrong.
|
||||||
// callback_->OnCaptureCompleted(nullptr), otherwise
|
|
||||||
// callback_->OnCaptureCompleted(frame) will be called.
|
|
||||||
std::unique_ptr<DesktopFrame> ProcessFrame(
|
std::unique_ptr<DesktopFrame> ProcessFrame(
|
||||||
const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
const DXGI_OUTDUPL_FRAME_INFO& frame_info,
|
||||||
IDXGIResource* resource);
|
IDXGIResource* resource);
|
||||||
|
|||||||
@ -39,14 +39,8 @@ const wchar_t kDwmapiLibraryName[] = L"dwmapi.dll";
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ScreenCapturerWinGdi::ScreenCapturerWinGdi(const DesktopCaptureOptions& options)
|
ScreenCapturerWinGdi::ScreenCapturerWinGdi(
|
||||||
: callback_(NULL),
|
const DesktopCaptureOptions& options) {
|
||||||
current_screen_id_(kFullDesktopScreenId),
|
|
||||||
desktop_dc_(NULL),
|
|
||||||
memory_dc_(NULL),
|
|
||||||
dwmapi_library_(NULL),
|
|
||||||
composition_func_(NULL),
|
|
||||||
set_thread_execution_state_failed_(false) {
|
|
||||||
if (options.disable_effects()) {
|
if (options.disable_effects()) {
|
||||||
// Load dwmapi.dll dynamically since it is not available on XP.
|
// Load dwmapi.dll dynamically since it is not available on XP.
|
||||||
if (!dwmapi_library_)
|
if (!dwmapi_library_)
|
||||||
@ -97,7 +91,7 @@ void ScreenCapturerWinGdi::Capture(const DesktopRegion& region) {
|
|||||||
PrepareCaptureResources();
|
PrepareCaptureResources();
|
||||||
|
|
||||||
if (!CaptureImage()) {
|
if (!CaptureImage()) {
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +124,7 @@ void ScreenCapturerWinGdi::Capture(const DesktopRegion& region) {
|
|||||||
helper_.set_size_most_recent(current_frame->size());
|
helper_.set_size_most_recent(current_frame->size());
|
||||||
|
|
||||||
// Emit the current frame.
|
// Emit the current frame.
|
||||||
DesktopFrame* frame = queue_.current_frame()->Share();
|
std::unique_ptr<DesktopFrame> frame = queue_.current_frame()->Share();
|
||||||
frame->set_dpi(DesktopVector(
|
frame->set_dpi(DesktopVector(
|
||||||
GetDeviceCaps(desktop_dc_, LOGPIXELSX),
|
GetDeviceCaps(desktop_dc_, LOGPIXELSX),
|
||||||
GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
|
GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
|
||||||
@ -139,7 +133,7 @@ void ScreenCapturerWinGdi::Capture(const DesktopRegion& region) {
|
|||||||
frame->set_capture_time_ms(
|
frame->set_capture_time_ms(
|
||||||
(rtc::TimeNanos() - capture_start_time_nanos) /
|
(rtc::TimeNanos() - capture_start_time_nanos) /
|
||||||
rtc::kNumNanosecsPerMillisec);
|
rtc::kNumNanosecsPerMillisec);
|
||||||
callback_->OnCaptureCompleted(frame);
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScreenCapturerWinGdi::GetScreenList(ScreenList* screens) {
|
bool ScreenCapturerWinGdi::GetScreenList(ScreenList* screens) {
|
||||||
@ -170,16 +164,16 @@ void ScreenCapturerWinGdi::PrepareCaptureResources() {
|
|||||||
// Switch to the desktop receiving user input if different from the current
|
// Switch to the desktop receiving user input if different from the current
|
||||||
// one.
|
// one.
|
||||||
std::unique_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
|
std::unique_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
|
||||||
if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
|
if (input_desktop && !desktop_.IsSame(*input_desktop)) {
|
||||||
// Release GDI resources otherwise SetThreadDesktop will fail.
|
// Release GDI resources otherwise SetThreadDesktop will fail.
|
||||||
if (desktop_dc_) {
|
if (desktop_dc_) {
|
||||||
ReleaseDC(NULL, desktop_dc_);
|
ReleaseDC(NULL, desktop_dc_);
|
||||||
desktop_dc_ = NULL;
|
desktop_dc_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memory_dc_) {
|
if (memory_dc_) {
|
||||||
DeleteDC(memory_dc_);
|
DeleteDC(memory_dc_);
|
||||||
memory_dc_ = NULL;
|
memory_dc_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If SetThreadDesktop() fails, the thread is still assigned a desktop.
|
// If SetThreadDesktop() fails, the thread is still assigned a desktop.
|
||||||
@ -188,7 +182,7 @@ void ScreenCapturerWinGdi::PrepareCaptureResources() {
|
|||||||
|
|
||||||
// Re-assert our vote to disable Aero.
|
// Re-assert our vote to disable Aero.
|
||||||
// See crbug.com/124018 and crbug.com/129906.
|
// See crbug.com/124018 and crbug.com/129906.
|
||||||
if (composition_func_ != NULL) {
|
if (composition_func_) {
|
||||||
(*composition_func_)(DWM_EC_DISABLECOMPOSITION);
|
(*composition_func_)(DWM_EC_DISABLECOMPOSITION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,20 +197,20 @@ void ScreenCapturerWinGdi::PrepareCaptureResources() {
|
|||||||
if (!screen_rect.equals(desktop_dc_rect_)) {
|
if (!screen_rect.equals(desktop_dc_rect_)) {
|
||||||
if (desktop_dc_) {
|
if (desktop_dc_) {
|
||||||
ReleaseDC(NULL, desktop_dc_);
|
ReleaseDC(NULL, desktop_dc_);
|
||||||
desktop_dc_ = NULL;
|
desktop_dc_ = nullptr;
|
||||||
}
|
}
|
||||||
if (memory_dc_) {
|
if (memory_dc_) {
|
||||||
DeleteDC(memory_dc_);
|
DeleteDC(memory_dc_);
|
||||||
memory_dc_ = NULL;
|
memory_dc_ = nullptr;
|
||||||
}
|
}
|
||||||
desktop_dc_rect_ = DesktopRect();
|
desktop_dc_rect_ = DesktopRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desktop_dc_ == NULL) {
|
if (!desktop_dc_) {
|
||||||
assert(memory_dc_ == NULL);
|
assert(!memory_dc_);
|
||||||
|
|
||||||
// Create GDI device contexts to capture from the desktop into memory.
|
// Create GDI device contexts to capture from the desktop into memory.
|
||||||
desktop_dc_ = GetDC(NULL);
|
desktop_dc_ = GetDC(nullptr);
|
||||||
if (!desktop_dc_)
|
if (!desktop_dc_)
|
||||||
abort();
|
abort();
|
||||||
memory_dc_ = CreateCompatibleDC(desktop_dc_);
|
memory_dc_ = CreateCompatibleDC(desktop_dc_);
|
||||||
@ -244,14 +238,14 @@ bool ScreenCapturerWinGdi::CaptureImage() {
|
|||||||
// may still be reading from them.
|
// may still be reading from them.
|
||||||
if (!queue_.current_frame() ||
|
if (!queue_.current_frame() ||
|
||||||
!queue_.current_frame()->size().equals(screen_rect.size())) {
|
!queue_.current_frame()->size().equals(screen_rect.size())) {
|
||||||
assert(desktop_dc_ != NULL);
|
assert(desktop_dc_);
|
||||||
assert(memory_dc_ != NULL);
|
assert(memory_dc_);
|
||||||
|
|
||||||
std::unique_ptr<DesktopFrame> buffer(DesktopFrameWin::Create(
|
std::unique_ptr<DesktopFrame> buffer = DesktopFrameWin::Create(
|
||||||
size, shared_memory_factory_.get(), desktop_dc_));
|
size, shared_memory_factory_.get(), desktop_dc_);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return false;
|
return false;
|
||||||
queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(buffer.release()));
|
queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(std::move(buffer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the target bitmap into the memory dc and copy the rect from desktop
|
// Select the target bitmap into the memory dc and copy the rect from desktop
|
||||||
@ -259,11 +253,9 @@ bool ScreenCapturerWinGdi::CaptureImage() {
|
|||||||
DesktopFrameWin* current = static_cast<DesktopFrameWin*>(
|
DesktopFrameWin* current = static_cast<DesktopFrameWin*>(
|
||||||
queue_.current_frame()->GetUnderlyingFrame());
|
queue_.current_frame()->GetUnderlyingFrame());
|
||||||
HGDIOBJ previous_object = SelectObject(memory_dc_, current->bitmap());
|
HGDIOBJ previous_object = SelectObject(memory_dc_, current->bitmap());
|
||||||
if (previous_object != NULL) {
|
if (previous_object) {
|
||||||
BitBlt(memory_dc_,
|
BitBlt(memory_dc_, 0, 0, screen_rect.width(), screen_rect.height(),
|
||||||
0, 0, screen_rect.width(), screen_rect.height(),
|
desktop_dc_, screen_rect.left(), screen_rect.top(),
|
||||||
desktop_dc_,
|
|
||||||
screen_rect.left(), screen_rect.top(),
|
|
||||||
SRCCOPY | CAPTUREBLT);
|
SRCCOPY | CAPTUREBLT);
|
||||||
|
|
||||||
// Select back the previously selected object to that the device contect
|
// Select back the previously selected object to that the device contect
|
||||||
|
|||||||
@ -56,9 +56,9 @@ class ScreenCapturerWinGdi : public ScreenCapturer {
|
|||||||
// Capture the current cursor shape.
|
// Capture the current cursor shape.
|
||||||
void CaptureCursor();
|
void CaptureCursor();
|
||||||
|
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory_;
|
std::unique_ptr<SharedMemoryFactory> shared_memory_factory_;
|
||||||
ScreenId current_screen_id_;
|
ScreenId current_screen_id_ = kFullDesktopScreenId;
|
||||||
std::wstring current_device_key_;
|
std::wstring current_device_key_;
|
||||||
|
|
||||||
// A thread-safe list of invalid rectangles, and the size of the most
|
// A thread-safe list of invalid rectangles, and the size of the most
|
||||||
@ -68,8 +68,8 @@ class ScreenCapturerWinGdi : public ScreenCapturer {
|
|||||||
ScopedThreadDesktop desktop_;
|
ScopedThreadDesktop desktop_;
|
||||||
|
|
||||||
// GDI resources used for screen capture.
|
// GDI resources used for screen capture.
|
||||||
HDC desktop_dc_;
|
HDC desktop_dc_ = NULL;
|
||||||
HDC memory_dc_;
|
HDC memory_dc_ = NULL;
|
||||||
|
|
||||||
// Queue of the frames buffers.
|
// Queue of the frames buffers.
|
||||||
ScreenCaptureFrameQueue<SharedDesktopFrame> queue_;
|
ScreenCaptureFrameQueue<SharedDesktopFrame> queue_;
|
||||||
@ -81,11 +81,11 @@ class ScreenCapturerWinGdi : public ScreenCapturer {
|
|||||||
// Class to calculate the difference between two screen bitmaps.
|
// Class to calculate the difference between two screen bitmaps.
|
||||||
std::unique_ptr<Differ> differ_;
|
std::unique_ptr<Differ> differ_;
|
||||||
|
|
||||||
HMODULE dwmapi_library_;
|
HMODULE dwmapi_library_ = NULL;
|
||||||
DwmEnableCompositionFunc composition_func_;
|
DwmEnableCompositionFunc composition_func_ = nullptr;
|
||||||
|
|
||||||
// Used to suppress duplicate logging of SetThreadExecutionState errors.
|
// Used to suppress duplicate logging of SetThreadExecutionState errors.
|
||||||
bool set_thread_execution_state_failed_;
|
bool set_thread_execution_state_failed_ = false;
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinGdi);
|
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinGdi);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -39,23 +39,7 @@ Atomic32 ScreenCapturerWinMagnifier::tls_index_(TLS_OUT_OF_INDEXES);
|
|||||||
|
|
||||||
ScreenCapturerWinMagnifier::ScreenCapturerWinMagnifier(
|
ScreenCapturerWinMagnifier::ScreenCapturerWinMagnifier(
|
||||||
std::unique_ptr<ScreenCapturer> fallback_capturer)
|
std::unique_ptr<ScreenCapturer> fallback_capturer)
|
||||||
: fallback_capturer_(std::move(fallback_capturer)),
|
: fallback_capturer_(std::move(fallback_capturer)) {}
|
||||||
fallback_capturer_started_(false),
|
|
||||||
callback_(NULL),
|
|
||||||
current_screen_id_(kFullDesktopScreenId),
|
|
||||||
excluded_window_(NULL),
|
|
||||||
set_thread_execution_state_failed_(false),
|
|
||||||
desktop_dc_(NULL),
|
|
||||||
mag_lib_handle_(NULL),
|
|
||||||
mag_initialize_func_(NULL),
|
|
||||||
mag_uninitialize_func_(NULL),
|
|
||||||
set_window_source_func_(NULL),
|
|
||||||
set_window_filter_list_func_(NULL),
|
|
||||||
set_image_scaling_callback_func_(NULL),
|
|
||||||
host_window_(NULL),
|
|
||||||
magnifier_window_(NULL),
|
|
||||||
magnifier_initialized_(false),
|
|
||||||
magnifier_capture_succeeded_(true) {}
|
|
||||||
|
|
||||||
ScreenCapturerWinMagnifier::~ScreenCapturerWinMagnifier() {
|
ScreenCapturerWinMagnifier::~ScreenCapturerWinMagnifier() {
|
||||||
// DestroyWindow must be called before MagUninitialize. magnifier_window_ is
|
// DestroyWindow must be called before MagUninitialize. magnifier_window_ is
|
||||||
@ -162,15 +146,14 @@ void ScreenCapturerWinMagnifier::Capture(const DesktopRegion& region) {
|
|||||||
helper_.set_size_most_recent(current_frame->size());
|
helper_.set_size_most_recent(current_frame->size());
|
||||||
|
|
||||||
// Emit the current frame.
|
// Emit the current frame.
|
||||||
DesktopFrame* frame = queue_.current_frame()->Share();
|
std::unique_ptr<DesktopFrame> frame = queue_.current_frame()->Share();
|
||||||
frame->set_dpi(DesktopVector(GetDeviceCaps(desktop_dc_, LOGPIXELSX),
|
frame->set_dpi(DesktopVector(GetDeviceCaps(desktop_dc_, LOGPIXELSX),
|
||||||
GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
|
GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
|
||||||
frame->mutable_updated_region()->Clear();
|
frame->mutable_updated_region()->Clear();
|
||||||
helper_.TakeInvalidRegion(frame->mutable_updated_region());
|
helper_.TakeInvalidRegion(frame->mutable_updated_region());
|
||||||
frame->set_capture_time_ms(
|
frame->set_capture_time_ms((rtc::TimeNanos() - capture_start_time_nanos) /
|
||||||
(rtc::TimeNanos() - capture_start_time_nanos) /
|
|
||||||
rtc::kNumNanosecsPerMillisec);
|
rtc::kNumNanosecsPerMillisec);
|
||||||
callback_->OnCaptureCompleted(frame);
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScreenCapturerWinMagnifier::GetScreenList(ScreenList* screens) {
|
bool ScreenCapturerWinMagnifier::GetScreenList(ScreenList* screens) {
|
||||||
@ -204,11 +187,8 @@ bool ScreenCapturerWinMagnifier::CaptureImage(const DesktopRect& rect) {
|
|||||||
|
|
||||||
// Set the magnifier control to cover the captured rect. The content of the
|
// Set the magnifier control to cover the captured rect. The content of the
|
||||||
// magnifier control will be the captured image.
|
// magnifier control will be the captured image.
|
||||||
BOOL result = SetWindowPos(magnifier_window_,
|
BOOL result = SetWindowPos(magnifier_window_, NULL, rect.left(), rect.top(),
|
||||||
NULL,
|
rect.width(), rect.height(), 0);
|
||||||
rect.left(), rect.top(),
|
|
||||||
rect.width(), rect.height(),
|
|
||||||
0);
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
LOG_F(LS_WARNING) << "Failed to call SetWindowPos: " << GetLastError()
|
LOG_F(LS_WARNING) << "Failed to call SetWindowPos: " << GetLastError()
|
||||||
<< ". Rect = {" << rect.left() << ", " << rect.top()
|
<< ". Rect = {" << rect.left() << ", " << rect.top()
|
||||||
@ -257,7 +237,7 @@ BOOL ScreenCapturerWinMagnifier::OnMagImageScalingCallback(
|
|||||||
bool ScreenCapturerWinMagnifier::InitializeMagnifier() {
|
bool ScreenCapturerWinMagnifier::InitializeMagnifier() {
|
||||||
assert(!magnifier_initialized_);
|
assert(!magnifier_initialized_);
|
||||||
|
|
||||||
desktop_dc_ = GetDC(NULL);
|
desktop_dc_ = GetDC(nullptr);
|
||||||
|
|
||||||
mag_lib_handle_ = LoadLibrary(L"Magnification.dll");
|
mag_lib_handle_ = LoadLibrary(L"Magnification.dll");
|
||||||
if (!mag_lib_handle_)
|
if (!mag_lib_handle_)
|
||||||
@ -291,7 +271,7 @@ bool ScreenCapturerWinMagnifier::InitializeMagnifier() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HMODULE hInstance = NULL;
|
HMODULE hInstance = nullptr;
|
||||||
result = GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
result = GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||||
reinterpret_cast<char*>(&DefWindowProc),
|
reinterpret_cast<char*>(&DefWindowProc),
|
||||||
@ -309,22 +289,16 @@ bool ScreenCapturerWinMagnifier::InitializeMagnifier() {
|
|||||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||||
wcex.lpfnWndProc = &DefWindowProc;
|
wcex.lpfnWndProc = &DefWindowProc;
|
||||||
wcex.hInstance = hInstance;
|
wcex.hInstance = hInstance;
|
||||||
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||||
wcex.lpszClassName = kMagnifierHostClass;
|
wcex.lpszClassName = kMagnifierHostClass;
|
||||||
|
|
||||||
// Ignore the error which may happen when the class is already registered.
|
// Ignore the error which may happen when the class is already registered.
|
||||||
RegisterClassEx(&wcex);
|
RegisterClassEx(&wcex);
|
||||||
|
|
||||||
// Create the host window.
|
// Create the host window.
|
||||||
host_window_ = CreateWindowEx(WS_EX_LAYERED,
|
host_window_ =
|
||||||
kMagnifierHostClass,
|
CreateWindowEx(WS_EX_LAYERED, kMagnifierHostClass, kHostWindowName, 0, 0,
|
||||||
kHostWindowName,
|
0, 0, 0, nullptr, nullptr, hInstance, nullptr);
|
||||||
0,
|
|
||||||
0, 0, 0, 0,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
hInstance,
|
|
||||||
NULL);
|
|
||||||
if (!host_window_) {
|
if (!host_window_) {
|
||||||
mag_uninitialize_func_();
|
mag_uninitialize_func_();
|
||||||
LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
|
LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
|
||||||
@ -333,14 +307,9 @@ bool ScreenCapturerWinMagnifier::InitializeMagnifier() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the magnifier control.
|
// Create the magnifier control.
|
||||||
magnifier_window_ = CreateWindow(kMagnifierWindowClass,
|
magnifier_window_ = CreateWindow(kMagnifierWindowClass, kMagnifierWindowName,
|
||||||
kMagnifierWindowName,
|
WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
|
||||||
WS_CHILD | WS_VISIBLE,
|
host_window_, nullptr, hInstance, nullptr);
|
||||||
0, 0, 0, 0,
|
|
||||||
host_window_,
|
|
||||||
NULL,
|
|
||||||
hInstance,
|
|
||||||
NULL);
|
|
||||||
if (!magnifier_window_) {
|
if (!magnifier_window_) {
|
||||||
mag_uninitialize_func_();
|
mag_uninitialize_func_();
|
||||||
LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
|
LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
|
||||||
@ -433,7 +402,7 @@ void ScreenCapturerWinMagnifier::CreateCurrentFrameIfNecessary(
|
|||||||
? SharedMemoryDesktopFrame::Create(size,
|
? SharedMemoryDesktopFrame::Create(size,
|
||||||
shared_memory_factory_.get())
|
shared_memory_factory_.get())
|
||||||
: std::unique_ptr<DesktopFrame>(new BasicDesktopFrame(size));
|
: std::unique_ptr<DesktopFrame>(new BasicDesktopFrame(size));
|
||||||
queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(frame.release()));
|
queue_.ReplaceCurrentFrame(SharedDesktopFrame::Wrap(std::move(frame)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -106,12 +106,12 @@ class ScreenCapturerWinMagnifier : public ScreenCapturer {
|
|||||||
static Atomic32 tls_index_;
|
static Atomic32 tls_index_;
|
||||||
|
|
||||||
std::unique_ptr<ScreenCapturer> fallback_capturer_;
|
std::unique_ptr<ScreenCapturer> fallback_capturer_;
|
||||||
bool fallback_capturer_started_;
|
bool fallback_capturer_started_ = false;
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
std::unique_ptr<SharedMemoryFactory> shared_memory_factory_;
|
std::unique_ptr<SharedMemoryFactory> shared_memory_factory_;
|
||||||
ScreenId current_screen_id_;
|
ScreenId current_screen_id_ = kFullDesktopScreenId;
|
||||||
std::wstring current_device_key_;
|
std::wstring current_device_key_;
|
||||||
HWND excluded_window_;
|
HWND excluded_window_ = NULL;
|
||||||
|
|
||||||
// A thread-safe list of invalid rectangles, and the size of the most
|
// A thread-safe list of invalid rectangles, and the size of the most
|
||||||
// recently captured screen.
|
// recently captured screen.
|
||||||
@ -124,31 +124,31 @@ class ScreenCapturerWinMagnifier : public ScreenCapturer {
|
|||||||
std::unique_ptr<Differ> differ_;
|
std::unique_ptr<Differ> differ_;
|
||||||
|
|
||||||
// Used to suppress duplicate logging of SetThreadExecutionState errors.
|
// Used to suppress duplicate logging of SetThreadExecutionState errors.
|
||||||
bool set_thread_execution_state_failed_;
|
bool set_thread_execution_state_failed_ = false;
|
||||||
|
|
||||||
ScopedThreadDesktop desktop_;
|
ScopedThreadDesktop desktop_;
|
||||||
|
|
||||||
// Used for getting the screen dpi.
|
// Used for getting the screen dpi.
|
||||||
HDC desktop_dc_;
|
HDC desktop_dc_ = NULL;
|
||||||
|
|
||||||
HMODULE mag_lib_handle_;
|
HMODULE mag_lib_handle_ = NULL;
|
||||||
MagInitializeFunc mag_initialize_func_;
|
MagInitializeFunc mag_initialize_func_ = nullptr;
|
||||||
MagUninitializeFunc mag_uninitialize_func_;
|
MagUninitializeFunc mag_uninitialize_func_ = nullptr;
|
||||||
MagSetWindowSourceFunc set_window_source_func_;
|
MagSetWindowSourceFunc set_window_source_func_ = nullptr;
|
||||||
MagSetWindowFilterListFunc set_window_filter_list_func_;
|
MagSetWindowFilterListFunc set_window_filter_list_func_ = nullptr;
|
||||||
MagSetImageScalingCallbackFunc set_image_scaling_callback_func_;
|
MagSetImageScalingCallbackFunc set_image_scaling_callback_func_ = nullptr;
|
||||||
|
|
||||||
// The hidden window hosting the magnifier control.
|
// The hidden window hosting the magnifier control.
|
||||||
HWND host_window_;
|
HWND host_window_ = NULL;
|
||||||
// The magnifier control that captures the screen.
|
// The magnifier control that captures the screen.
|
||||||
HWND magnifier_window_;
|
HWND magnifier_window_ = NULL;
|
||||||
|
|
||||||
// True if the magnifier control has been successfully initialized.
|
// True if the magnifier control has been successfully initialized.
|
||||||
bool magnifier_initialized_;
|
bool magnifier_initialized_ = false;
|
||||||
|
|
||||||
// True if the last OnMagImageScalingCallback was called and handled
|
// True if the last OnMagImageScalingCallback was called and handled
|
||||||
// successfully. Reset at the beginning of each CaptureImage call.
|
// successfully. Reset at the beginning of each CaptureImage call.
|
||||||
bool magnifier_capture_succeeded_;
|
bool magnifier_capture_succeeded_ = true;
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinMagnifier);
|
RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinMagnifier);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -32,7 +32,7 @@ namespace {
|
|||||||
// Returns true if the window exists.
|
// Returns true if the window exists.
|
||||||
bool IsWindowValid(CGWindowID id) {
|
bool IsWindowValid(CGWindowID id) {
|
||||||
CFArrayRef window_id_array =
|
CFArrayRef window_id_array =
|
||||||
CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
|
CFArrayCreate(nullptr, reinterpret_cast<const void**>(&id), 1, nullptr);
|
||||||
CFArrayRef window_array =
|
CFArrayRef window_array =
|
||||||
CGWindowListCreateDescriptionFromArray(window_id_array);
|
CGWindowListCreateDescriptionFromArray(window_id_array);
|
||||||
bool valid = window_array && CFArrayGetCount(window_array);
|
bool valid = window_array && CFArrayGetCount(window_array);
|
||||||
@ -58,10 +58,10 @@ class WindowCapturerMac : public WindowCapturer {
|
|||||||
void Capture(const DesktopRegion& region) override;
|
void Capture(const DesktopRegion& region) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
|
|
||||||
// The window being captured.
|
// The window being captured.
|
||||||
CGWindowID window_id_;
|
CGWindowID window_id_ = 0;
|
||||||
|
|
||||||
rtc::scoped_refptr<FullScreenChromeWindowDetector>
|
rtc::scoped_refptr<FullScreenChromeWindowDetector>
|
||||||
full_screen_chrome_window_detector_;
|
full_screen_chrome_window_detector_;
|
||||||
@ -69,15 +69,12 @@ class WindowCapturerMac : public WindowCapturer {
|
|||||||
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac);
|
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac);
|
||||||
};
|
};
|
||||||
|
|
||||||
WindowCapturerMac::WindowCapturerMac(rtc::scoped_refptr<
|
WindowCapturerMac::WindowCapturerMac(
|
||||||
FullScreenChromeWindowDetector> full_screen_chrome_window_detector)
|
rtc::scoped_refptr<FullScreenChromeWindowDetector>
|
||||||
: callback_(NULL),
|
full_screen_chrome_window_detector)
|
||||||
window_id_(0),
|
: full_screen_chrome_window_detector_(full_screen_chrome_window_detector) {}
|
||||||
full_screen_chrome_window_detector_(full_screen_chrome_window_detector) {
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowCapturerMac::~WindowCapturerMac() {
|
WindowCapturerMac::~WindowCapturerMac() {}
|
||||||
}
|
|
||||||
|
|
||||||
bool WindowCapturerMac::GetWindowList(WindowList* windows) {
|
bool WindowCapturerMac::GetWindowList(WindowList* windows) {
|
||||||
// Only get on screen, non-desktop windows.
|
// Only get on screen, non-desktop windows.
|
||||||
@ -142,11 +139,11 @@ bool WindowCapturerMac::BringSelectedWindowToFront() {
|
|||||||
CGWindowID ids[1];
|
CGWindowID ids[1];
|
||||||
ids[0] = window_id_;
|
ids[0] = window_id_;
|
||||||
CFArrayRef window_id_array =
|
CFArrayRef window_id_array =
|
||||||
CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
|
CFArrayCreate(nullptr, reinterpret_cast<const void**>(&ids), 1, nullptr);
|
||||||
|
|
||||||
CFArrayRef window_array =
|
CFArrayRef window_array =
|
||||||
CGWindowListCreateDescriptionFromArray(window_id_array);
|
CGWindowListCreateDescriptionFromArray(window_id_array);
|
||||||
if (window_array == NULL || 0 == CFArrayGetCount(window_array)) {
|
if (!window_array || 0 == CFArrayGetCount(window_array)) {
|
||||||
// Could not find the window. It might have been closed.
|
// Could not find the window. It might have been closed.
|
||||||
LOG(LS_INFO) << "Window not found";
|
LOG(LS_INFO) << "Window not found";
|
||||||
CFRelease(window_id_array);
|
CFRelease(window_id_array);
|
||||||
@ -181,7 +178,7 @@ void WindowCapturerMac::Start(Callback* callback) {
|
|||||||
|
|
||||||
void WindowCapturerMac::Capture(const DesktopRegion& region) {
|
void WindowCapturerMac::Capture(const DesktopRegion& region) {
|
||||||
if (!IsWindowValid(window_id_)) {
|
if (!IsWindowValid(window_id_)) {
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +196,7 @@ void WindowCapturerMac::Capture(const DesktopRegion& region) {
|
|||||||
on_screen_window, kCGWindowImageBoundsIgnoreFraming);
|
on_screen_window, kCGWindowImageBoundsIgnoreFraming);
|
||||||
|
|
||||||
if (!window_image) {
|
if (!window_image) {
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +204,7 @@ void WindowCapturerMac::Capture(const DesktopRegion& region) {
|
|||||||
if (bits_per_pixel != 32) {
|
if (bits_per_pixel != 32) {
|
||||||
LOG(LS_ERROR) << "Unsupported window image depth: " << bits_per_pixel;
|
LOG(LS_ERROR) << "Unsupported window image depth: " << bits_per_pixel;
|
||||||
CFRelease(window_image);
|
CFRelease(window_image);
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,8 +212,8 @@ void WindowCapturerMac::Capture(const DesktopRegion& region) {
|
|||||||
int height = CGImageGetHeight(window_image);
|
int height = CGImageGetHeight(window_image);
|
||||||
CGDataProviderRef provider = CGImageGetDataProvider(window_image);
|
CGDataProviderRef provider = CGImageGetDataProvider(window_image);
|
||||||
CFDataRef cf_data = CGDataProviderCopyData(provider);
|
CFDataRef cf_data = CGDataProviderCopyData(provider);
|
||||||
DesktopFrame* frame = new BasicDesktopFrame(
|
std::unique_ptr<DesktopFrame> frame(
|
||||||
DesktopSize(width, height));
|
new BasicDesktopFrame(DesktopSize(width, height)));
|
||||||
|
|
||||||
int src_stride = CGImageGetBytesPerRow(window_image);
|
int src_stride = CGImageGetBytesPerRow(window_image);
|
||||||
const uint8_t* src_data = CFDataGetBytePtr(cf_data);
|
const uint8_t* src_data = CFDataGetBytePtr(cf_data);
|
||||||
@ -231,7 +228,7 @@ void WindowCapturerMac::Capture(const DesktopRegion& region) {
|
|||||||
frame->mutable_updated_region()->SetRect(
|
frame->mutable_updated_region()->SetRect(
|
||||||
DesktopRect::MakeSize(frame->size()));
|
DesktopRect::MakeSize(frame->size()));
|
||||||
|
|
||||||
callback_->OnCaptureCompleted(frame);
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
||||||
|
|
||||||
if (full_screen_chrome_window_detector_)
|
if (full_screen_chrome_window_detector_)
|
||||||
full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_);
|
full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_);
|
||||||
|
|||||||
@ -34,17 +34,13 @@ class WindowCapturerNull : public WindowCapturer {
|
|||||||
void Capture(const DesktopRegion& region) override;
|
void Capture(const DesktopRegion& region) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerNull);
|
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerNull);
|
||||||
};
|
};
|
||||||
|
|
||||||
WindowCapturerNull::WindowCapturerNull()
|
WindowCapturerNull::WindowCapturerNull() {}
|
||||||
: callback_(NULL) {
|
WindowCapturerNull::~WindowCapturerNull() {}
|
||||||
}
|
|
||||||
|
|
||||||
WindowCapturerNull::~WindowCapturerNull() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WindowCapturerNull::GetWindowList(WindowList* windows) {
|
bool WindowCapturerNull::GetWindowList(WindowList* windows) {
|
||||||
// Not implemented yet.
|
// Not implemented yet.
|
||||||
@ -70,7 +66,7 @@ void WindowCapturerNull::Start(Callback* callback) {
|
|||||||
|
|
||||||
void WindowCapturerNull::Capture(const DesktopRegion& region) {
|
void WindowCapturerNull::Capture(const DesktopRegion& region) {
|
||||||
// Not implemented yet.
|
// Not implemented yet.
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -31,7 +31,10 @@ class WindowCapturerTest : public testing::Test,
|
|||||||
void TearDown() override {}
|
void TearDown() override {}
|
||||||
|
|
||||||
// DesktopCapturer::Callback interface
|
// DesktopCapturer::Callback interface
|
||||||
void OnCaptureCompleted(DesktopFrame* frame) override { frame_.reset(frame); }
|
void OnCaptureResult(DesktopCapturer::Result result,
|
||||||
|
std::unique_ptr<DesktopFrame> frame) override {
|
||||||
|
frame_ = std::move(frame);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<WindowCapturer> capturer_;
|
std::unique_ptr<WindowCapturer> capturer_;
|
||||||
|
|||||||
@ -95,11 +95,11 @@ class WindowCapturerWin : public WindowCapturer {
|
|||||||
void Capture(const DesktopRegion& region) override;
|
void Capture(const DesktopRegion& region) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
|
|
||||||
// HWND and HDC for the currently selected window or NULL if window is not
|
// HWND and HDC for the currently selected window or nullptr if window is not
|
||||||
// selected.
|
// selected.
|
||||||
HWND window_;
|
HWND window_ = nullptr;
|
||||||
|
|
||||||
DesktopSize previous_size_;
|
DesktopSize previous_size_;
|
||||||
|
|
||||||
@ -112,13 +112,8 @@ class WindowCapturerWin : public WindowCapturer {
|
|||||||
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerWin);
|
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerWin);
|
||||||
};
|
};
|
||||||
|
|
||||||
WindowCapturerWin::WindowCapturerWin()
|
WindowCapturerWin::WindowCapturerWin() {}
|
||||||
: callback_(NULL),
|
WindowCapturerWin::~WindowCapturerWin() {}
|
||||||
window_(NULL) {
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowCapturerWin::~WindowCapturerWin() {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WindowCapturerWin::GetWindowList(WindowList* windows) {
|
bool WindowCapturerWin::GetWindowList(WindowList* windows) {
|
||||||
WindowList result;
|
WindowList result;
|
||||||
@ -168,13 +163,13 @@ void WindowCapturerWin::Start(Callback* callback) {
|
|||||||
void WindowCapturerWin::Capture(const DesktopRegion& region) {
|
void WindowCapturerWin::Capture(const DesktopRegion& region) {
|
||||||
if (!window_) {
|
if (!window_) {
|
||||||
LOG(LS_ERROR) << "Window hasn't been selected: " << GetLastError();
|
LOG(LS_ERROR) << "Window hasn't been selected: " << GetLastError();
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop capturing if the window has been closed.
|
// Stop capturing if the window has been closed.
|
||||||
if (!IsWindow(window_)) {
|
if (!IsWindow(window_)) {
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,12 +177,13 @@ void WindowCapturerWin::Capture(const DesktopRegion& region) {
|
|||||||
// behavior on mace. Window can be temporarily invisible during the
|
// behavior on mace. Window can be temporarily invisible during the
|
||||||
// transition of full screen mode on/off.
|
// transition of full screen mode on/off.
|
||||||
if (IsIconic(window_) || !IsWindowVisible(window_)) {
|
if (IsIconic(window_) || !IsWindowVisible(window_)) {
|
||||||
BasicDesktopFrame* frame = new BasicDesktopFrame(DesktopSize(1, 1));
|
std::unique_ptr<DesktopFrame> frame(
|
||||||
|
new BasicDesktopFrame(DesktopSize(1, 1)));
|
||||||
memset(frame->data(), 0, frame->stride() * frame->size().height());
|
memset(frame->data(), 0, frame->stride() * frame->size().height());
|
||||||
|
|
||||||
previous_size_ = frame->size();
|
previous_size_ = frame->size();
|
||||||
window_size_map_[window_] = previous_size_;
|
window_size_map_[window_] = previous_size_;
|
||||||
callback_->OnCaptureCompleted(frame);
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,22 +191,22 @@ void WindowCapturerWin::Capture(const DesktopRegion& region) {
|
|||||||
DesktopRect cropped_rect;
|
DesktopRect cropped_rect;
|
||||||
if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) {
|
if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) {
|
||||||
LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
|
LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HDC window_dc = GetWindowDC(window_);
|
HDC window_dc = GetWindowDC(window_);
|
||||||
if (!window_dc) {
|
if (!window_dc) {
|
||||||
LOG(LS_WARNING) << "Failed to get window DC: " << GetLastError();
|
LOG(LS_WARNING) << "Failed to get window DC: " << GetLastError();
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<DesktopFrameWin> frame(
|
std::unique_ptr<DesktopFrameWin> frame(
|
||||||
DesktopFrameWin::Create(cropped_rect.size(), NULL, window_dc));
|
DesktopFrameWin::Create(cropped_rect.size(), nullptr, window_dc));
|
||||||
if (!frame.get()) {
|
if (!frame.get()) {
|
||||||
ReleaseDC(window_, window_dc);
|
ReleaseDC(window_, window_dc);
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +259,7 @@ void WindowCapturerWin::Capture(const DesktopRegion& region) {
|
|||||||
frame.reset();
|
frame.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
callback_->OnCaptureCompleted(frame.release());
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
42
webrtc/modules/desktop_capture/window_capturer_x11.cc
Executable file → Normal file
42
webrtc/modules/desktop_capture/window_capturer_x11.cc
Executable file → Normal file
@ -36,10 +36,7 @@ namespace {
|
|||||||
template <class PropertyType>
|
template <class PropertyType>
|
||||||
class XWindowProperty {
|
class XWindowProperty {
|
||||||
public:
|
public:
|
||||||
XWindowProperty(Display* display, Window window, Atom property)
|
XWindowProperty(Display* display, Window window, Atom property) {
|
||||||
: is_valid_(false),
|
|
||||||
size_(0),
|
|
||||||
data_(NULL) {
|
|
||||||
const int kBitsPerByte = 8;
|
const int kBitsPerByte = 8;
|
||||||
Atom actual_type;
|
Atom actual_type;
|
||||||
int actual_format;
|
int actual_format;
|
||||||
@ -49,7 +46,7 @@ class XWindowProperty {
|
|||||||
&actual_format, &size_,
|
&actual_format, &size_,
|
||||||
&bytes_after, &data_);
|
&bytes_after, &data_);
|
||||||
if (status != Success) {
|
if (status != Success) {
|
||||||
data_ = NULL;
|
data_ = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sizeof(PropertyType) * kBitsPerByte != actual_format) {
|
if (sizeof(PropertyType) * kBitsPerByte != actual_format) {
|
||||||
@ -78,9 +75,9 @@ class XWindowProperty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_valid_;
|
bool is_valid_ = false;
|
||||||
unsigned long size_; // NOLINT: type required by XGetWindowProperty
|
unsigned long size_ = 0; // NOLINT: type required by XGetWindowProperty
|
||||||
unsigned char* data_;
|
unsigned char* data_ = nullptr;
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(XWindowProperty);
|
RTC_DISALLOW_COPY_AND_ASSIGN(XWindowProperty);
|
||||||
};
|
};
|
||||||
@ -117,26 +114,23 @@ class WindowCapturerLinux : public WindowCapturer,
|
|||||||
// Returns window title for the specified X |window|.
|
// Returns window title for the specified X |window|.
|
||||||
bool GetWindowTitle(::Window window, std::string* title);
|
bool GetWindowTitle(::Window window, std::string* title);
|
||||||
|
|
||||||
Callback* callback_;
|
Callback* callback_ = nullptr;
|
||||||
|
|
||||||
rtc::scoped_refptr<SharedXDisplay> x_display_;
|
rtc::scoped_refptr<SharedXDisplay> x_display_;
|
||||||
|
|
||||||
Atom wm_state_atom_;
|
Atom wm_state_atom_;
|
||||||
Atom window_type_atom_;
|
Atom window_type_atom_;
|
||||||
Atom normal_window_type_atom_;
|
Atom normal_window_type_atom_;
|
||||||
bool has_composite_extension_;
|
bool has_composite_extension_ = false;
|
||||||
|
|
||||||
::Window selected_window_;
|
::Window selected_window_ = 0;
|
||||||
XServerPixelBuffer x_server_pixel_buffer_;
|
XServerPixelBuffer x_server_pixel_buffer_;
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux);
|
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux);
|
||||||
};
|
};
|
||||||
|
|
||||||
WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options)
|
WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options)
|
||||||
: callback_(NULL),
|
: x_display_(options.x_display()) {
|
||||||
x_display_(options.x_display()),
|
|
||||||
has_composite_extension_(false),
|
|
||||||
selected_window_(0) {
|
|
||||||
// Create Atoms so we don't need to do it every time they are used.
|
// Create Atoms so we don't need to do it every time they are used.
|
||||||
wm_state_atom_ = XInternAtom(display(), "WM_STATE", True);
|
wm_state_atom_ = XInternAtom(display(), "WM_STATE", True);
|
||||||
window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True);
|
window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True);
|
||||||
@ -280,7 +274,7 @@ void WindowCapturerLinux::Start(Callback* callback) {
|
|||||||
void WindowCapturerLinux::Capture(const DesktopRegion& region) {
|
void WindowCapturerLinux::Capture(const DesktopRegion& region) {
|
||||||
if (!x_server_pixel_buffer_.IsWindowValid()) {
|
if (!x_server_pixel_buffer_.IsWindowValid()) {
|
||||||
LOG(LS_INFO) << "The window is no longer valid.";
|
LOG(LS_INFO) << "The window is no longer valid.";
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,21 +285,21 @@ void WindowCapturerLinux::Capture(const DesktopRegion& region) {
|
|||||||
// visible on screen and not covered by any other window. This is not
|
// visible on screen and not covered by any other window. This is not
|
||||||
// something we want so instead, just bail out.
|
// something we want so instead, just bail out.
|
||||||
LOG(LS_INFO) << "No Xcomposite extension detected.";
|
LOG(LS_INFO) << "No Xcomposite extension detected.";
|
||||||
callback_->OnCaptureCompleted(NULL);
|
callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopFrame* frame =
|
std::unique_ptr<DesktopFrame> frame(
|
||||||
new BasicDesktopFrame(x_server_pixel_buffer_.window_size());
|
new BasicDesktopFrame(x_server_pixel_buffer_.window_size()));
|
||||||
|
|
||||||
x_server_pixel_buffer_.Synchronize();
|
x_server_pixel_buffer_.Synchronize();
|
||||||
x_server_pixel_buffer_.CaptureRect(DesktopRect::MakeSize(frame->size()),
|
x_server_pixel_buffer_.CaptureRect(DesktopRect::MakeSize(frame->size()),
|
||||||
frame);
|
frame.get());
|
||||||
|
|
||||||
frame->mutable_updated_region()->SetRect(
|
frame->mutable_updated_region()->SetRect(
|
||||||
DesktopRect::MakeSize(frame->size()));
|
DesktopRect::MakeSize(frame->size()));
|
||||||
|
|
||||||
callback_->OnCaptureCompleted(frame);
|
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WindowCapturerLinux::HandleXEvent(const XEvent& event) {
|
bool WindowCapturerLinux::HandleXEvent(const XEvent& event) {
|
||||||
@ -399,12 +393,12 @@ bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) {
|
|||||||
int status;
|
int status;
|
||||||
bool result = false;
|
bool result = false;
|
||||||
XTextProperty window_name;
|
XTextProperty window_name;
|
||||||
window_name.value = NULL;
|
window_name.value = nullptr;
|
||||||
if (window) {
|
if (window) {
|
||||||
status = XGetWMName(display(), window, &window_name);
|
status = XGetWMName(display(), window, &window_name);
|
||||||
if (status && window_name.value && window_name.nitems) {
|
if (status && window_name.value && window_name.nitems) {
|
||||||
int cnt;
|
int cnt;
|
||||||
char **list = NULL;
|
char** list = nullptr;
|
||||||
status = Xutf8TextPropertyToTextList(display(), &window_name, &list,
|
status = Xutf8TextPropertyToTextList(display(), &window_name, &list,
|
||||||
&cnt);
|
&cnt);
|
||||||
if (status >= Success && cnt && *list) {
|
if (status >= Success && cnt && *list) {
|
||||||
@ -429,7 +423,7 @@ bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) {
|
|||||||
// static
|
// static
|
||||||
WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
|
WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
|
||||||
if (!options.x_display())
|
if (!options.x_display())
|
||||||
return NULL;
|
return nullptr;
|
||||||
return new WindowCapturerLinux(options);
|
return new WindowCapturerLinux(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user