WebRTC is now using C++14 so there is no need to use the Abseil version of std::make_unique. This CL has been created with the following steps: git grep -l absl::make_unique | sort | uniq > /tmp/make_unique.txt git grep -l absl::WrapUnique | sort | uniq > /tmp/wrap_unique.txt git grep -l "#include <memory>" | sort | uniq > /tmp/memory.txt diff --new-line-format="" --unchanged-line-format="" \ /tmp/make_unique.txt /tmp/wrap_unique.txt | sort | \ uniq > /tmp/only_make_unique.txt diff --new-line-format="" --unchanged-line-format="" \ /tmp/only_make_unique.txt /tmp/memory.txt | \ xargs grep -l "absl/memory" > /tmp/add-memory.txt git grep -l "\babsl::make_unique\b" | \ xargs sed -i "s/\babsl::make_unique\b/std::make_unique/g" git checkout PRESUBMIT.py abseil-in-webrtc.md cat /tmp/add-memory.txt | \ xargs sed -i \ 's/#include "absl\/memory\/memory.h"/#include <memory>/g' git cl format # Manual fix order of the new inserted #include <memory> cat /tmp/only_make_unique | xargs grep -l "#include <memory>" | \ xargs sed -i '/#include "absl\/memory\/memory.h"/d' git ls-files | grep BUILD.gn | \ xargs sed -i '/\/\/third_party\/abseil-cpp\/absl\/memory/d' python tools_webrtc/gn_check_autofix.py \ -m tryserver.webrtc -b linux_rel # Repead the gn_check_autofix step for other platforms git ls-files | grep BUILD.gn | \ xargs sed -i 's/absl\/memory:memory/absl\/memory/g' git cl format Bug: webrtc:10945 Change-Id: I3fe28ea80f4dd3ba3cf28effd151d5e1f19aff89 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/153221 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Alessio Bazzica <alessiob@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29209}
212 lines
7.6 KiB
C++
212 lines
7.6 KiB
C++
/*
|
|
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/desktop_capture/desktop_and_cursor_composer.h"
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "modules/desktop_capture/desktop_capturer.h"
|
|
#include "modules/desktop_capture/desktop_frame.h"
|
|
#include "modules/desktop_capture/mouse_cursor.h"
|
|
#include "modules/desktop_capture/mouse_cursor_monitor.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/constructor_magic.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
// Helper function that blends one image into another. Source image must be
|
|
// pre-multiplied with the alpha channel. Destination is assumed to be opaque.
|
|
void AlphaBlend(uint8_t* dest,
|
|
int dest_stride,
|
|
const uint8_t* src,
|
|
int src_stride,
|
|
const DesktopSize& size) {
|
|
for (int y = 0; y < size.height(); ++y) {
|
|
for (int x = 0; x < size.width(); ++x) {
|
|
uint32_t base_alpha = 255 - src[x * DesktopFrame::kBytesPerPixel + 3];
|
|
if (base_alpha == 255) {
|
|
continue;
|
|
} else if (base_alpha == 0) {
|
|
memcpy(dest + x * DesktopFrame::kBytesPerPixel,
|
|
src + x * DesktopFrame::kBytesPerPixel,
|
|
DesktopFrame::kBytesPerPixel);
|
|
} else {
|
|
dest[x * DesktopFrame::kBytesPerPixel] =
|
|
dest[x * DesktopFrame::kBytesPerPixel] * base_alpha / 255 +
|
|
src[x * DesktopFrame::kBytesPerPixel];
|
|
dest[x * DesktopFrame::kBytesPerPixel + 1] =
|
|
dest[x * DesktopFrame::kBytesPerPixel + 1] * base_alpha / 255 +
|
|
src[x * DesktopFrame::kBytesPerPixel + 1];
|
|
dest[x * DesktopFrame::kBytesPerPixel + 2] =
|
|
dest[x * DesktopFrame::kBytesPerPixel + 2] * base_alpha / 255 +
|
|
src[x * DesktopFrame::kBytesPerPixel + 2];
|
|
}
|
|
}
|
|
src += src_stride;
|
|
dest += dest_stride;
|
|
}
|
|
}
|
|
|
|
// DesktopFrame wrapper that draws mouse on a frame and restores original
|
|
// content before releasing the underlying frame.
|
|
class DesktopFrameWithCursor : public DesktopFrame {
|
|
public:
|
|
// Takes ownership of |frame|.
|
|
DesktopFrameWithCursor(std::unique_ptr<DesktopFrame> frame,
|
|
const MouseCursor& cursor,
|
|
const DesktopVector& position);
|
|
~DesktopFrameWithCursor() override;
|
|
|
|
private:
|
|
const std::unique_ptr<DesktopFrame> original_frame_;
|
|
|
|
DesktopVector restore_position_;
|
|
std::unique_ptr<DesktopFrame> restore_frame_;
|
|
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(DesktopFrameWithCursor);
|
|
};
|
|
|
|
DesktopFrameWithCursor::DesktopFrameWithCursor(
|
|
std::unique_ptr<DesktopFrame> frame,
|
|
const MouseCursor& cursor,
|
|
const DesktopVector& position)
|
|
: DesktopFrame(frame->size(),
|
|
frame->stride(),
|
|
frame->data(),
|
|
frame->shared_memory()),
|
|
original_frame_(std::move(frame)) {
|
|
MoveFrameInfoFrom(original_frame_.get());
|
|
|
|
DesktopVector image_pos = position.subtract(cursor.hotspot());
|
|
DesktopRect target_rect = DesktopRect::MakeSize(cursor.image()->size());
|
|
target_rect.Translate(image_pos);
|
|
DesktopVector target_origin = target_rect.top_left();
|
|
target_rect.IntersectWith(DesktopRect::MakeSize(size()));
|
|
|
|
if (target_rect.is_empty())
|
|
return;
|
|
|
|
// Copy original screen content under cursor to |restore_frame_|.
|
|
restore_position_ = target_rect.top_left();
|
|
restore_frame_.reset(new BasicDesktopFrame(target_rect.size()));
|
|
restore_frame_->CopyPixelsFrom(*this, target_rect.top_left(),
|
|
DesktopRect::MakeSize(restore_frame_->size()));
|
|
|
|
// Blit the cursor.
|
|
uint8_t* target_rect_data = reinterpret_cast<uint8_t*>(data()) +
|
|
target_rect.top() * stride() +
|
|
target_rect.left() * DesktopFrame::kBytesPerPixel;
|
|
DesktopVector origin_shift = target_rect.top_left().subtract(target_origin);
|
|
AlphaBlend(target_rect_data, stride(),
|
|
cursor.image()->data() +
|
|
origin_shift.y() * cursor.image()->stride() +
|
|
origin_shift.x() * DesktopFrame::kBytesPerPixel,
|
|
cursor.image()->stride(), target_rect.size());
|
|
}
|
|
|
|
DesktopFrameWithCursor::~DesktopFrameWithCursor() {
|
|
// Restore original content of the frame.
|
|
if (restore_frame_) {
|
|
DesktopRect target_rect = DesktopRect::MakeSize(restore_frame_->size());
|
|
target_rect.Translate(restore_position_);
|
|
CopyPixelsFrom(restore_frame_->data(), restore_frame_->stride(),
|
|
target_rect);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
DesktopAndCursorComposer::DesktopAndCursorComposer(
|
|
std::unique_ptr<DesktopCapturer> desktop_capturer,
|
|
const DesktopCaptureOptions& options)
|
|
: DesktopAndCursorComposer(desktop_capturer.release(),
|
|
MouseCursorMonitor::Create(options).release()) {}
|
|
|
|
DesktopAndCursorComposer::DesktopAndCursorComposer(
|
|
DesktopCapturer* desktop_capturer,
|
|
MouseCursorMonitor* mouse_monitor)
|
|
: desktop_capturer_(desktop_capturer), mouse_monitor_(mouse_monitor) {
|
|
RTC_DCHECK(desktop_capturer_);
|
|
}
|
|
|
|
DesktopAndCursorComposer::~DesktopAndCursorComposer() = default;
|
|
|
|
void DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) {
|
|
callback_ = callback;
|
|
if (mouse_monitor_)
|
|
mouse_monitor_->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION);
|
|
desktop_capturer_->Start(this);
|
|
}
|
|
|
|
void DesktopAndCursorComposer::SetSharedMemoryFactory(
|
|
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) {
|
|
desktop_capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
|
|
}
|
|
|
|
void DesktopAndCursorComposer::CaptureFrame() {
|
|
if (mouse_monitor_)
|
|
mouse_monitor_->Capture();
|
|
desktop_capturer_->CaptureFrame();
|
|
}
|
|
|
|
void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) {
|
|
desktop_capturer_->SetExcludedWindow(window);
|
|
}
|
|
|
|
void DesktopAndCursorComposer::OnCaptureResult(
|
|
DesktopCapturer::Result result,
|
|
std::unique_ptr<DesktopFrame> frame) {
|
|
if (frame && cursor_) {
|
|
if (frame->rect().Contains(cursor_position_) &&
|
|
!desktop_capturer_->IsOccluded(cursor_position_)) {
|
|
DesktopVector relative_position =
|
|
cursor_position_.subtract(frame->top_left());
|
|
#if defined(WEBRTC_MAC)
|
|
// On OSX, the logical(DIP) and physical coordinates are used mixingly.
|
|
// For example, the captured cursor has its size in physical pixels(2x)
|
|
// and location in logical(DIP) pixels on Retina monitor. This will cause
|
|
// problem when the desktop is mixed with Retina and non-Retina monitors.
|
|
// So we use DIP pixel for all location info and compensate with the scale
|
|
// factor of current frame to the |relative_position|.
|
|
const float scale = frame->scale_factor();
|
|
relative_position.set(relative_position.x() * scale,
|
|
relative_position.y() * scale);
|
|
#endif
|
|
frame = std::make_unique<DesktopFrameWithCursor>(
|
|
std::move(frame), *cursor_, relative_position);
|
|
}
|
|
}
|
|
|
|
callback_->OnCaptureResult(result, std::move(frame));
|
|
}
|
|
|
|
void DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) {
|
|
cursor_.reset(cursor);
|
|
}
|
|
|
|
void DesktopAndCursorComposer::OnMouseCursorPosition(
|
|
MouseCursorMonitor::CursorState state,
|
|
const DesktopVector& position) {
|
|
RTC_NOTREACHED();
|
|
}
|
|
|
|
void DesktopAndCursorComposer::OnMouseCursorPosition(
|
|
const DesktopVector& position) {
|
|
cursor_position_ = position;
|
|
}
|
|
|
|
} // namespace webrtc
|