Line data Source code
1 : /*
2 : * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "webrtc/modules/desktop_capture/desktop_and_cursor_composer.h"
12 :
13 : #include <string.h>
14 :
15 : #include "webrtc/base/constructormagic.h"
16 : #include "webrtc/modules/desktop_capture/desktop_capturer.h"
17 : #include "webrtc/modules/desktop_capture/desktop_frame.h"
18 : #include "webrtc/modules/desktop_capture/mouse_cursor.h"
19 :
20 : namespace webrtc {
21 :
22 : namespace {
23 :
24 : // Helper function that blends one image into another. Source image must be
25 : // pre-multiplied with the alpha channel. Destination is assumed to be opaque.
26 0 : void AlphaBlend(uint8_t* dest, int dest_stride,
27 : const uint8_t* src, int src_stride,
28 : const DesktopSize& size) {
29 0 : for (int y = 0; y < size.height(); ++y) {
30 0 : for (int x = 0; x < size.width(); ++x) {
31 0 : uint32_t base_alpha = 255 - src[x * DesktopFrame::kBytesPerPixel + 3];
32 0 : if (base_alpha == 255) {
33 0 : continue;
34 0 : } else if (base_alpha == 0) {
35 0 : memcpy(dest + x * DesktopFrame::kBytesPerPixel,
36 0 : src + x * DesktopFrame::kBytesPerPixel,
37 0 : DesktopFrame::kBytesPerPixel);
38 : } else {
39 0 : dest[x * DesktopFrame::kBytesPerPixel] =
40 0 : dest[x * DesktopFrame::kBytesPerPixel] * base_alpha / 255 +
41 0 : src[x * DesktopFrame::kBytesPerPixel];
42 0 : dest[x * DesktopFrame::kBytesPerPixel + 1] =
43 0 : dest[x * DesktopFrame::kBytesPerPixel + 1] * base_alpha / 255 +
44 0 : src[x * DesktopFrame::kBytesPerPixel + 1];
45 0 : dest[x * DesktopFrame::kBytesPerPixel + 2] =
46 0 : dest[x * DesktopFrame::kBytesPerPixel + 2] * base_alpha / 255 +
47 0 : src[x * DesktopFrame::kBytesPerPixel + 2];
48 : }
49 : }
50 0 : src += src_stride;
51 0 : dest += dest_stride;
52 : }
53 0 : }
54 :
55 : // DesktopFrame wrapper that draws mouse on a frame and restores original
56 : // content before releasing the underlying frame.
57 : class DesktopFrameWithCursor : public DesktopFrame {
58 : public:
59 : // Takes ownership of |frame|.
60 : DesktopFrameWithCursor(std::unique_ptr<DesktopFrame> frame,
61 : const MouseCursor& cursor,
62 : const DesktopVector& position);
63 : ~DesktopFrameWithCursor() override;
64 :
65 : private:
66 : std::unique_ptr<DesktopFrame> original_frame_;
67 :
68 : DesktopVector restore_position_;
69 : std::unique_ptr<DesktopFrame> restore_frame_;
70 :
71 : RTC_DISALLOW_COPY_AND_ASSIGN(DesktopFrameWithCursor);
72 : };
73 :
74 0 : DesktopFrameWithCursor::DesktopFrameWithCursor(
75 : std::unique_ptr<DesktopFrame> frame,
76 : const MouseCursor& cursor,
77 0 : const DesktopVector& position)
78 0 : : DesktopFrame(frame->size(),
79 : frame->stride(),
80 : frame->data(),
81 0 : frame->shared_memory()) {
82 0 : set_dpi(frame->dpi());
83 0 : set_capture_time_ms(frame->capture_time_ms());
84 0 : mutable_updated_region()->Swap(frame->mutable_updated_region());
85 0 : original_frame_ = std::move(frame);
86 :
87 0 : DesktopVector image_pos = position.subtract(cursor.hotspot());
88 0 : DesktopRect target_rect = DesktopRect::MakeSize(cursor.image()->size());
89 0 : target_rect.Translate(image_pos);
90 0 : DesktopVector target_origin = target_rect.top_left();
91 0 : target_rect.IntersectWith(DesktopRect::MakeSize(size()));
92 :
93 0 : if (target_rect.is_empty())
94 0 : return;
95 :
96 : // Copy original screen content under cursor to |restore_frame_|.
97 0 : restore_position_ = target_rect.top_left();
98 0 : restore_frame_.reset(new BasicDesktopFrame(target_rect.size()));
99 0 : restore_frame_->CopyPixelsFrom(*this, target_rect.top_left(),
100 0 : DesktopRect::MakeSize(restore_frame_->size()));
101 :
102 : // Blit the cursor.
103 0 : uint8_t* target_rect_data = reinterpret_cast<uint8_t*>(data()) +
104 0 : target_rect.top() * stride() +
105 0 : target_rect.left() * DesktopFrame::kBytesPerPixel;
106 0 : DesktopVector origin_shift = target_rect.top_left().subtract(target_origin);
107 0 : AlphaBlend(target_rect_data, stride(),
108 0 : cursor.image()->data() +
109 0 : origin_shift.y() * cursor.image()->stride() +
110 0 : origin_shift.x() * DesktopFrame::kBytesPerPixel,
111 : cursor.image()->stride(),
112 0 : target_rect.size());
113 : }
114 :
115 0 : DesktopFrameWithCursor::~DesktopFrameWithCursor() {
116 : // Restore original content of the frame.
117 0 : if (restore_frame_.get()) {
118 0 : DesktopRect target_rect = DesktopRect::MakeSize(restore_frame_->size());
119 0 : target_rect.Translate(restore_position_);
120 0 : CopyPixelsFrom(restore_frame_->data(), restore_frame_->stride(),
121 0 : target_rect);
122 : }
123 0 : }
124 :
125 : } // namespace
126 :
127 0 : DesktopAndCursorComposer::DesktopAndCursorComposer(
128 : DesktopCapturer* desktop_capturer,
129 0 : MouseCursorMonitor* mouse_monitor)
130 : : desktop_capturer_(desktop_capturer),
131 0 : mouse_monitor_(mouse_monitor) {
132 0 : }
133 :
134 0 : DesktopAndCursorComposer::~DesktopAndCursorComposer() {}
135 :
136 0 : void DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) {
137 0 : callback_ = callback;
138 0 : if (mouse_monitor_.get())
139 0 : mouse_monitor_->Start(this, MouseCursorMonitor::SHAPE_AND_POSITION);
140 0 : desktop_capturer_->Start(this);
141 0 : }
142 :
143 0 : void DesktopAndCursorComposer::Stop() {
144 0 : desktop_capturer_->Stop();
145 0 : if (mouse_monitor_.get())
146 0 : mouse_monitor_->Stop();
147 0 : callback_ = NULL;
148 0 : }
149 :
150 0 : void DesktopAndCursorComposer::SetSharedMemoryFactory(
151 : std::unique_ptr<SharedMemoryFactory> shared_memory_factory) {
152 0 : desktop_capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
153 0 : }
154 :
155 0 : void DesktopAndCursorComposer::CaptureFrame() {
156 0 : if (mouse_monitor_.get())
157 0 : mouse_monitor_->Capture();
158 0 : desktop_capturer_->CaptureFrame();
159 0 : }
160 :
161 0 : void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) {
162 0 : desktop_capturer_->SetExcludedWindow(window);
163 0 : }
164 :
165 0 : void DesktopAndCursorComposer::OnCaptureResult(
166 : DesktopCapturer::Result result,
167 : std::unique_ptr<DesktopFrame> frame) {
168 0 : if (frame && cursor_ && cursor_state_ == MouseCursorMonitor::INSIDE) {
169 0 : frame = std::unique_ptr<DesktopFrameWithCursor>(new DesktopFrameWithCursor(
170 0 : std::move(frame), *cursor_, cursor_position_));
171 : }
172 :
173 0 : callback_->OnCaptureResult(result, std::move(frame));
174 0 : }
175 :
176 0 : void DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) {
177 0 : cursor_.reset(cursor);
178 0 : }
179 :
180 0 : void DesktopAndCursorComposer::OnMouseCursorPosition(
181 : MouseCursorMonitor::CursorState state,
182 : const DesktopVector& position) {
183 0 : cursor_state_ = state;
184 0 : cursor_position_ = position;
185 0 : }
186 :
187 : } // namespace webrtc
|