Cleanup shared memory handling in DesktopCapturer interface.

Previously shared memory buffers for DesktopCapturer were created
using DesktopCapturer::Callback::CreateSharedBuffer(). That made it
difficult to proxy DesktopCapturer interface from one thread to another.
This CL adds SharedBufferFactory interface that's allowed to be called
on a background thread. This also simplifies clients that don't
need to use shared memory, as they no longer need to override
CreateSharedBuffer().

Review URL: https://codereview.webrtc.org/1678073003

Cr-Commit-Position: refs/heads/master@{#11543}
This commit is contained in:
sergeyu 2016-02-09 15:13:26 -08:00 committed by Commit bot
parent c815c60f8a
commit cc9669c6b8
19 changed files with 159 additions and 79 deletions

View File

@ -31,6 +31,11 @@ void CroppingWindowCapturer::Start(DesktopCapturer::Callback* callback) {
window_capturer_->Start(callback);
}
void CroppingWindowCapturer::SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) {
window_capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
}
void CroppingWindowCapturer::Capture(const DesktopRegion& region) {
if (ShouldUseScreenCapturer()) {
if (!screen_capturer_.get()) {
@ -69,10 +74,6 @@ bool CroppingWindowCapturer::BringSelectedWindowToFront() {
return window_capturer_->BringSelectedWindowToFront();
}
SharedMemory* CroppingWindowCapturer::CreateSharedMemory(size_t size) {
return callback_->CreateSharedMemory(size);
}
void CroppingWindowCapturer::OnCaptureCompleted(DesktopFrame* frame) {
rtc::scoped_ptr<DesktopFrame> screen_frame(frame);

View File

@ -29,6 +29,8 @@ class CroppingWindowCapturer : public WindowCapturer,
// DesktopCapturer implementation.
void Start(DesktopCapturer::Callback* callback) override;
void SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) override;
void Capture(const DesktopRegion& region) override;
void SetExcludedWindow(WindowId window) override;
@ -39,7 +41,6 @@ class CroppingWindowCapturer : public WindowCapturer,
// DesktopCapturer::Callback implementation, passed to |screen_capturer_| to
// intercept the capture result.
SharedMemory* CreateSharedMemory(size_t size) override;
void OnCaptureCompleted(DesktopFrame* frame) override;
protected:

View File

@ -136,6 +136,11 @@ void DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) {
desktop_capturer_->Start(this);
}
void DesktopAndCursorComposer::SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) {
desktop_capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
}
void DesktopAndCursorComposer::Capture(const DesktopRegion& region) {
if (mouse_monitor_.get())
mouse_monitor_->Capture();
@ -146,10 +151,6 @@ void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) {
desktop_capturer_->SetExcludedWindow(window);
}
SharedMemory* DesktopAndCursorComposer::CreateSharedMemory(size_t size) {
return callback_->CreateSharedMemory(size);
}
void DesktopAndCursorComposer::OnCaptureCompleted(DesktopFrame* frame) {
if (frame && cursor_.get() && cursor_state_ == MouseCursorMonitor::INSIDE) {
DesktopFrameWithCursor* frame_with_cursor =

View File

@ -20,8 +20,8 @@ namespace webrtc {
// A wrapper for DesktopCapturer that also captures mouse using specified
// MouseCursorMonitor and renders it on the generated streams.
class DesktopAndCursorComposer : public DesktopCapturer,
public DesktopCapturer::Callback,
public MouseCursorMonitor::Callback {
public DesktopCapturer::Callback,
public MouseCursorMonitor::Callback {
public:
// Creates a new blender that captures mouse cursor using |mouse_monitor| and
// renders it into the frames generated by |desktop_capturer|. If
@ -33,12 +33,13 @@ class DesktopAndCursorComposer : public DesktopCapturer,
// DesktopCapturer interface.
void Start(DesktopCapturer::Callback* callback) override;
void SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) override;
void Capture(const DesktopRegion& region) override;
void SetExcludedWindow(WindowId window) override;
private:
// DesktopCapturer::Callback interface.
SharedMemory* CreateSharedMemory(size_t size) override;
void OnCaptureCompleted(DesktopFrame* frame) override;
// MouseCursorMonitor::Callback interface.

View File

@ -168,8 +168,6 @@ class DesktopAndCursorComposerTest : public testing::Test,
}
// DesktopCapturer::Callback interface
SharedMemory* CreateSharedMemory(size_t size) override { return NULL; }
void OnCaptureCompleted(DesktopFrame* frame) override { frame_.reset(frame); }
protected:

View File

@ -13,13 +13,14 @@
#include <stddef.h>
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
#include "webrtc/modules/desktop_capture/shared_memory.h"
namespace webrtc {
class DesktopFrame;
class DesktopRegion;
class SharedMemory;
// Abstract interface for screen and window capturers.
class DesktopCapturer {
@ -27,10 +28,10 @@ class DesktopCapturer {
// Interface that must be implemented by the DesktopCapturer consumers.
class Callback {
public:
// Creates a new shared memory buffer for a frame create by the capturer.
// Should return null shared memory is not used for captured frames (in that
// case the capturer will allocate memory on the heap).
virtual SharedMemory* CreateSharedMemory(size_t size) = 0;
// Deprecated.
// TODO(sergeyu): Remove this method once all references to it are removed
// from chromium.
virtual SharedMemory* CreateSharedMemory(size_t size) { return nullptr; }
// Called after a frame has been captured. Handler must take ownership of
// |frame|. If capture has failed for any reason |frame| is set to NULL
@ -47,6 +48,13 @@ class DesktopCapturer {
// valid until capturer is destroyed.
virtual void Start(Callback* callback) = 0;
// Sets SharedMemoryFactory that will be used to create buffers for the
// captured frames. The factory can be invoked on a thread other than the one
// where Capture() is called. It will be destroyed on the same thread. Shared
// memory is currently supported only by some DesktopCapturer implementations.
virtual void SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) {}
// Captures next frame. |region| specifies region of the capture target that
// should be fresh in the resulting frame. The frame may also include fresh
// data for areas outside |region|. In that case capturer will include these

View File

@ -77,15 +77,38 @@ DesktopFrame* BasicDesktopFrame::CopyOf(const DesktopFrame& frame) {
return result;
}
// static
rtc::scoped_ptr<DesktopFrame> SharedMemoryDesktopFrame::Create(
DesktopSize size,
SharedMemoryFactory* shared_memory_factory) {
size_t buffer_size =
size.width() * size.height() * DesktopFrame::kBytesPerPixel;
rtc::scoped_ptr<SharedMemory> shared_memory;
shared_memory = shared_memory_factory->CreateSharedMemory(buffer_size);
if (!shared_memory)
return nullptr;
return rtc_make_scoped_ptr(new SharedMemoryDesktopFrame(
size, size.width() * DesktopFrame::kBytesPerPixel,
std::move(shared_memory)));
}
SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(DesktopSize size,
int stride,
SharedMemory* shared_memory)
: DesktopFrame(size,
stride,
reinterpret_cast<uint8_t*>(shared_memory->data()),
shared_memory) {}
SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(
DesktopSize size,
int stride,
SharedMemory* shared_memory)
: DesktopFrame(size, stride,
rtc::scoped_ptr<SharedMemory> shared_memory)
: DesktopFrame(size,
stride,
reinterpret_cast<uint8_t*>(shared_memory->data()),
shared_memory) {
}
shared_memory.release()) {}
SharedMemoryDesktopFrame::~SharedMemoryDesktopFrame() {
delete shared_memory_;

View File

@ -110,10 +110,18 @@ class BasicDesktopFrame : public DesktopFrame {
// A DesktopFrame that stores data in shared memory.
class SharedMemoryDesktopFrame : public DesktopFrame {
public:
static rtc::scoped_ptr<DesktopFrame> Create(
DesktopSize size,
SharedMemoryFactory* shared_memory_factory);
// Takes ownership of |shared_memory|.
// TODO(sergeyu): Remove this constructor and keep the second one.
SharedMemoryDesktopFrame(DesktopSize size,
int stride,
SharedMemory* shared_memory);
SharedMemoryDesktopFrame(DesktopSize size,
int stride,
rtc::scoped_ptr<SharedMemory> shared_memory);
~SharedMemoryDesktopFrame() override;
private:

View File

@ -10,6 +10,8 @@
#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
#include <utility>
#include "webrtc/system_wrappers/include/logging.h"
namespace webrtc {
@ -17,22 +19,23 @@ namespace webrtc {
DesktopFrameWin::DesktopFrameWin(DesktopSize size,
int stride,
uint8_t* data,
SharedMemory* shared_memory,
rtc::scoped_ptr<SharedMemory> shared_memory,
HBITMAP bitmap)
: DesktopFrame(size, stride, data, shared_memory),
: DesktopFrame(size, stride, data, shared_memory.get()),
bitmap_(bitmap),
owned_shared_memory_(shared_memory_) {
}
owned_shared_memory_(std::move(shared_memory)) {}
DesktopFrameWin::~DesktopFrameWin() {
DeleteObject(bitmap_);
}
// static
DesktopFrameWin* DesktopFrameWin::Create(DesktopSize size,
SharedMemory* shared_memory,
HDC hdc) {
DesktopFrameWin* DesktopFrameWin::Create(
DesktopSize size,
SharedMemoryFactory* shared_memory_factory,
HDC hdc) {
int bytes_per_row = size.width() * kBytesPerPixel;
int buffer_size = bytes_per_row * size.height();
// Describe a device independent bitmap (DIB) that is the size of the desktop.
BITMAPINFO bmi = {};
@ -43,21 +46,24 @@ DesktopFrameWin* DesktopFrameWin::Create(DesktopSize size,
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biSizeImage = bytes_per_row * size.height();
HANDLE section_handle = NULL;
if (shared_memory)
section_handle = shared_memory->handle();
void* data = NULL;
rtc::scoped_ptr<SharedMemory> shared_memory;
HANDLE section_handle = nullptr;
if (shared_memory_factory) {
shared_memory = shared_memory_factory->CreateSharedMemory(buffer_size);
if (shared_memory)
section_handle = shared_memory->handle();
}
void* data = nullptr;
HBITMAP bitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &data,
section_handle, 0);
if (!bitmap) {
LOG(LS_WARNING) << "Failed to allocate new window frame " << GetLastError();
delete shared_memory;
return NULL;
return nullptr;
}
return new DesktopFrameWin(size, bytes_per_row,
reinterpret_cast<uint8_t*>(data),
shared_memory, bitmap);
std::move(shared_memory), bitmap);
}
} // namespace webrtc

View File

@ -25,7 +25,7 @@ class DesktopFrameWin : public DesktopFrame {
public:
virtual ~DesktopFrameWin();
static DesktopFrameWin* Create(DesktopSize size,
SharedMemory* shared_memory,
SharedMemoryFactory* shared_memory_factory,
HDC hdc);
HBITMAP bitmap() { return bitmap_; }
@ -34,7 +34,7 @@ class DesktopFrameWin : public DesktopFrame {
DesktopFrameWin(DesktopSize size,
int stride,
uint8_t* data,
SharedMemory* shared_memory,
rtc::scoped_ptr<SharedMemory> shared_memory,
HBITMAP bitmap);
HBITMAP bitmap_;

View File

@ -80,10 +80,6 @@ TEST_F(ScreenCapturerMacTest, Capture) {
.WillOnce(Invoke(this, &ScreenCapturerMacTest::CaptureDoneCallback1))
.WillOnce(Invoke(this, &ScreenCapturerMacTest::CaptureDoneCallback2));
EXPECT_CALL(callback_, CreateSharedMemory(_))
.Times(AnyNumber())
.WillRepeatedly(Return(static_cast<SharedMemory*>(NULL)));
SCOPED_TRACE("");
capturer_->Start(&callback_);

View File

@ -35,7 +35,6 @@ class MockScreenCapturerCallback : public ScreenCapturer::Callback {
MockScreenCapturerCallback() {}
virtual ~MockScreenCapturerCallback() {}
MOCK_METHOD1(CreateSharedMemory, SharedMemory*(size_t));
MOCK_METHOD1(OnCaptureCompleted, void(DesktopFrame*));
private:

View File

@ -28,8 +28,6 @@ namespace webrtc {
class ScreenCapturerTest : public testing::Test {
public:
SharedMemory* CreateSharedMemory(size_t size);
void SetUp() override {
capturer_.reset(
ScreenCapturer::Create(DesktopCaptureOptions::CreateDefault()));
@ -54,9 +52,18 @@ class FakeSharedMemory : public SharedMemory {
RTC_DISALLOW_COPY_AND_ASSIGN(FakeSharedMemory);
};
SharedMemory* ScreenCapturerTest::CreateSharedMemory(size_t size) {
return new FakeSharedMemory(new char[size], size);
}
class FakeSharedMemoryFactory : public SharedMemoryFactory {
public:
FakeSharedMemoryFactory() {}
~FakeSharedMemoryFactory() override {}
rtc::scoped_ptr<SharedMemory> CreateSharedMemory(size_t size) override {
return rtc_make_scoped_ptr(new FakeSharedMemory(new char[size], size));
}
private:
RTC_DISALLOW_COPY_AND_ASSIGN(FakeSharedMemoryFactory);
};
TEST_F(ScreenCapturerTest, GetScreenListAndSelectScreen) {
webrtc::ScreenCapturer::ScreenList screens;
@ -77,10 +84,6 @@ TEST_F(ScreenCapturerTest, Capture) {
EXPECT_CALL(callback_, OnCaptureCompleted(_))
.WillOnce(SaveArg<0>(&frame));
EXPECT_CALL(callback_, CreateSharedMemory(_))
.Times(AnyNumber())
.WillRepeatedly(Return(static_cast<SharedMemory*>(NULL)));
capturer_->Start(&callback_);
capturer_->Capture(DesktopRegion());
@ -109,11 +112,9 @@ TEST_F(ScreenCapturerTest, UseSharedBuffers) {
EXPECT_CALL(callback_, OnCaptureCompleted(_))
.WillOnce(SaveArg<0>(&frame));
EXPECT_CALL(callback_, CreateSharedMemory(_))
.Times(AnyNumber())
.WillRepeatedly(Invoke(this, &ScreenCapturerTest::CreateSharedMemory));
capturer_->Start(&callback_);
capturer_->SetSharedMemoryFactory(
rtc_make_scoped_ptr(new FakeSharedMemoryFactory()));
capturer_->Capture(DesktopRegion());
ASSERT_TRUE(frame);

View File

@ -17,6 +17,7 @@
#include <windows.h>
#endif
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/typedefs.h"
@ -26,8 +27,8 @@ namespace webrtc {
// parameters of the buffer, but doesn't have any logic to allocate or destroy
// the actual buffer. DesktopCapturer consumers that need to use shared memory
// for video frames must extend this class with creation and destruction logic
// specific for the target platform and then implement
// DesktopCapturer::Delegate::CreateSharedMemory() as appropriate.
// specific for the target platform and then call
// DesktopCapturer::SetSharedMemoryFactory().
class SharedMemory {
public:
#if defined(WEBRTC_WIN)
@ -62,6 +63,18 @@ class SharedMemory {
RTC_DISALLOW_COPY_AND_ASSIGN(SharedMemory);
};
// Interface used to create SharedMemory instances.
class SharedMemoryFactory {
public:
SharedMemoryFactory() {}
virtual ~SharedMemoryFactory() {}
virtual rtc::scoped_ptr<SharedMemory> CreateSharedMemory(size_t size) = 0;
private:
RTC_DISALLOW_COPY_AND_ASSIGN(SharedMemoryFactory);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_DESKTOP_CAPTURE_SHARED_MEMORY_H_

View File

@ -12,6 +12,8 @@
#include <assert.h>
#include <utility>
#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
#include "webrtc/modules/desktop_capture/desktop_frame.h"
#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
@ -34,6 +36,22 @@ const UINT DWM_EC_ENABLECOMPOSITION = 1;
const wchar_t kDwmapiLibraryName[] = L"dwmapi.dll";
// SharedMemoryFactory that creates SharedMemory using the deprecated
// DesktopCapturer::Callback::CreateSharedMemory().
class CallbackSharedMemoryFactory : public SharedMemoryFactory {
public:
CallbackSharedMemoryFactory(DesktopCapturer::Callback* callback)
: callback_(callback) {}
~CallbackSharedMemoryFactory() override {}
rtc::scoped_ptr<SharedMemory> CreateSharedMemory(size_t size) override {
return rtc_make_scoped_ptr(callback_->CreateSharedMemory(size));
}
private:
DesktopCapturer::Callback* callback_;
};
} // namespace
ScreenCapturerWinGdi::ScreenCapturerWinGdi(const DesktopCaptureOptions& options)
@ -70,6 +88,11 @@ ScreenCapturerWinGdi::~ScreenCapturerWinGdi() {
FreeLibrary(dwmapi_library_);
}
void ScreenCapturerWinGdi::SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) {
shared_memory_factory_ = std::move(shared_memory_factory);
}
void ScreenCapturerWinGdi::Capture(const DesktopRegion& region) {
TickTime capture_start_time = TickTime::Now();
@ -148,6 +171,8 @@ void ScreenCapturerWinGdi::Start(Callback* callback) {
assert(callback);
callback_ = callback;
if (!shared_memory_factory_)
shared_memory_factory_.reset(new CallbackSharedMemoryFactory(callback));
// Vote to disable Aero composited desktop effects while capturing. Windows
// will restore Aero automatically if the process exits. This has no effect
@ -237,12 +262,8 @@ bool ScreenCapturerWinGdi::CaptureImage() {
assert(desktop_dc_ != NULL);
assert(memory_dc_ != NULL);
size_t buffer_size = size.width() * size.height() *
DesktopFrame::kBytesPerPixel;
SharedMemory* shared_memory = callback_->CreateSharedMemory(buffer_size);
rtc::scoped_ptr<DesktopFrame> buffer(
DesktopFrameWin::Create(size, shared_memory, desktop_dc_));
rtc::scoped_ptr<DesktopFrame> buffer(DesktopFrameWin::Create(
size, shared_memory_factory_.get(), desktop_dc_));
if (!buffer.get())
return false;
queue_.ReplaceCurrentFrame(buffer.release());

View File

@ -34,6 +34,8 @@ class ScreenCapturerWinGdi : public ScreenCapturer {
// Overridden from ScreenCapturer:
void Start(Callback* callback) override;
void SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) override;
void Capture(const DesktopRegion& region) override;
bool GetScreenList(ScreenList* screens) override;
bool SelectScreen(ScreenId id) override;
@ -52,6 +54,7 @@ class ScreenCapturerWinGdi : public ScreenCapturer {
void CaptureCursor();
Callback* callback_;
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory_;
ScreenId current_screen_id_;
std::wstring current_device_key_;

View File

@ -81,6 +81,11 @@ void ScreenCapturerWinMagnifier::Start(Callback* callback) {
InitializeMagnifier();
}
void ScreenCapturerWinMagnifier::SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) {
shared_memory_factory_ = std::move(shared_memory_factory);
}
void ScreenCapturerWinMagnifier::Capture(const DesktopRegion& region) {
TickTime capture_start_time = TickTime::Now();
@ -422,18 +427,12 @@ void ScreenCapturerWinMagnifier::CreateCurrentFrameIfNecessary(
// Note that we can't reallocate other buffers at this point, since the caller
// may still be reading from them.
if (!queue_.current_frame() || !queue_.current_frame()->size().equals(size)) {
size_t buffer_size =
size.width() * size.height() * DesktopFrame::kBytesPerPixel;
SharedMemory* shared_memory = callback_->CreateSharedMemory(buffer_size);
rtc::scoped_ptr<DesktopFrame> buffer;
if (shared_memory) {
buffer.reset(new SharedMemoryDesktopFrame(
size, size.width() * DesktopFrame::kBytesPerPixel, shared_memory));
} else {
buffer.reset(new BasicDesktopFrame(size));
}
queue_.ReplaceCurrentFrame(buffer.release());
rtc::scoped_ptr<DesktopFrame> frame =
shared_memory_factory_
? SharedMemoryDesktopFrame::Create(size,
shared_memory_factory_.get())
: rtc::scoped_ptr<DesktopFrame>(new BasicDesktopFrame(size));
queue_.ReplaceCurrentFrame(frame.release());
}
}

View File

@ -44,6 +44,8 @@ class ScreenCapturerWinMagnifier : public ScreenCapturer {
// Overridden from ScreenCapturer:
void Start(Callback* callback) override;
void SetSharedMemoryFactory(
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) override;
void Capture(const DesktopRegion& region) override;
bool GetScreenList(ScreenList* screens) override;
bool SelectScreen(ScreenId id) override;
@ -104,6 +106,7 @@ class ScreenCapturerWinMagnifier : public ScreenCapturer {
rtc::scoped_ptr<ScreenCapturer> fallback_capturer_;
bool fallback_capturer_started_;
Callback* callback_;
rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory_;
ScreenId current_screen_id_;
std::wstring current_device_key_;
HWND excluded_window_;

View File

@ -30,8 +30,6 @@ class WindowCapturerTest : public testing::Test,
void TearDown() override {}
// DesktopCapturer::Callback interface
SharedMemory* CreateSharedMemory(size_t size) override { return NULL; }
void OnCaptureCompleted(DesktopFrame* frame) override { frame_.reset(frame); }
protected: