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/modules/desktop_capture/desktop_capturer.h"
16 #include "webrtc/modules/desktop_capture/desktop_frame.h"
17 #include "webrtc/modules/desktop_capture/mouse_cursor.h"
18
19 namespace webrtc {
20
21 namespace {
22
23 // Helper function that blends one image into another. Source image must be
24 // pre-multiplied with the alpha channel. Destination is assumed to be opaque.
AlphaBlend(uint8_t * dest,int dest_stride,const uint8_t * src,int src_stride,const DesktopSize & size)25 void AlphaBlend(uint8_t* dest, int dest_stride,
26 const uint8_t* src, int src_stride,
27 const DesktopSize& size) {
28 for (int y = 0; y < size.height(); ++y) {
29 for (int x = 0; x < size.width(); ++x) {
30 uint32_t base_alpha = 255 - src[x * DesktopFrame::kBytesPerPixel + 3];
31 if (base_alpha == 255) {
32 continue;
33 } else if (base_alpha == 0) {
34 memcpy(dest + x * DesktopFrame::kBytesPerPixel,
35 src + x * DesktopFrame::kBytesPerPixel,
36 DesktopFrame::kBytesPerPixel);
37 } else {
38 dest[x * DesktopFrame::kBytesPerPixel] =
39 dest[x * DesktopFrame::kBytesPerPixel] * base_alpha / 255 +
40 src[x * DesktopFrame::kBytesPerPixel];
41 dest[x * DesktopFrame::kBytesPerPixel + 1] =
42 dest[x * DesktopFrame::kBytesPerPixel + 1] * base_alpha / 255 +
43 src[x * DesktopFrame::kBytesPerPixel + 1];
44 dest[x * DesktopFrame::kBytesPerPixel + 2] =
45 dest[x * DesktopFrame::kBytesPerPixel + 2] * base_alpha / 255 +
46 src[x * DesktopFrame::kBytesPerPixel + 2];
47 }
48 }
49 src += src_stride;
50 dest += dest_stride;
51 }
52 }
53
54 // DesktopFrame wrapper that draws mouse on a frame and restores original
55 // content before releasing the underlying frame.
56 class DesktopFrameWithCursor : public DesktopFrame {
57 public:
58 // Takes ownership of |frame|.
59 DesktopFrameWithCursor(DesktopFrame* frame,
60 const MouseCursor& cursor,
61 const DesktopVector& position);
62 virtual ~DesktopFrameWithCursor();
63
64 private:
65 rtc::scoped_ptr<DesktopFrame> original_frame_;
66
67 DesktopVector restore_position_;
68 rtc::scoped_ptr<DesktopFrame> restore_frame_;
69
70 RTC_DISALLOW_COPY_AND_ASSIGN(DesktopFrameWithCursor);
71 };
72
DesktopFrameWithCursor(DesktopFrame * frame,const MouseCursor & cursor,const DesktopVector & position)73 DesktopFrameWithCursor::DesktopFrameWithCursor(DesktopFrame* frame,
74 const MouseCursor& cursor,
75 const DesktopVector& position)
76 : DesktopFrame(frame->size(), frame->stride(),
77 frame->data(), frame->shared_memory()),
78 original_frame_(frame) {
79 set_dpi(frame->dpi());
80 set_capture_time_ms(frame->capture_time_ms());
81 mutable_updated_region()->Swap(frame->mutable_updated_region());
82
83 DesktopVector image_pos = position.subtract(cursor.hotspot());
84 DesktopRect target_rect = DesktopRect::MakeSize(cursor.image()->size());
85 target_rect.Translate(image_pos);
86 DesktopVector target_origin = target_rect.top_left();
87 target_rect.IntersectWith(DesktopRect::MakeSize(size()));
88
89 if (target_rect.is_empty())
90 return;
91
92 // Copy original screen content under cursor to |restore_frame_|.
93 restore_position_ = target_rect.top_left();
94 restore_frame_.reset(new BasicDesktopFrame(target_rect.size()));
95 restore_frame_->CopyPixelsFrom(*this, target_rect.top_left(),
96 DesktopRect::MakeSize(restore_frame_->size()));
97
98 // Blit the cursor.
99 uint8_t* target_rect_data = reinterpret_cast<uint8_t*>(data()) +
100 target_rect.top() * stride() +
101 target_rect.left() * DesktopFrame::kBytesPerPixel;
102 DesktopVector origin_shift = target_rect.top_left().subtract(target_origin);
103 AlphaBlend(target_rect_data, stride(),
104 cursor.image()->data() +
105 origin_shift.y() * cursor.image()->stride() +
106 origin_shift.x() * DesktopFrame::kBytesPerPixel,
107 cursor.image()->stride(),
108 target_rect.size());
109 }
110
~DesktopFrameWithCursor()111 DesktopFrameWithCursor::~DesktopFrameWithCursor() {
112 // Restore original content of the frame.
113 if (restore_frame_.get()) {
114 DesktopRect target_rect = DesktopRect::MakeSize(restore_frame_->size());
115 target_rect.Translate(restore_position_);
116 CopyPixelsFrom(restore_frame_->data(), restore_frame_->stride(),
117 target_rect);
118 }
119 }
120
121 } // namespace
122
DesktopAndCursorComposer(DesktopCapturer * desktop_capturer,MouseCursorMonitor * mouse_monitor)123 DesktopAndCursorComposer::DesktopAndCursorComposer(
124 DesktopCapturer* desktop_capturer,
125 MouseCursorMonitor* mouse_monitor)
126 : desktop_capturer_(desktop_capturer),
127 mouse_monitor_(mouse_monitor) {
128 }
129
~DesktopAndCursorComposer()130 DesktopAndCursorComposer::~DesktopAndCursorComposer() {}
131
Start(DesktopCapturer::Callback * callback)132 void DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) {
133 callback_ = callback;
134 if (mouse_monitor_.get())
135 mouse_monitor_->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION);
136 desktop_capturer_->Start(this);
137 }
138
Capture(const DesktopRegion & region)139 void DesktopAndCursorComposer::Capture(const DesktopRegion& region) {
140 if (mouse_monitor_.get())
141 mouse_monitor_->Capture();
142 desktop_capturer_->Capture(region);
143 }
144
SetExcludedWindow(WindowId window)145 void DesktopAndCursorComposer::SetExcludedWindow(WindowId window) {
146 desktop_capturer_->SetExcludedWindow(window);
147 }
148
CreateSharedMemory(size_t size)149 SharedMemory* DesktopAndCursorComposer::CreateSharedMemory(size_t size) {
150 return callback_->CreateSharedMemory(size);
151 }
152
OnCaptureCompleted(DesktopFrame * frame)153 void DesktopAndCursorComposer::OnCaptureCompleted(DesktopFrame* frame) {
154 if (frame && cursor_.get() && cursor_state_ == MouseCursorMonitor::INSIDE) {
155 DesktopFrameWithCursor* frame_with_cursor =
156 new DesktopFrameWithCursor(frame, *cursor_, cursor_position_);
157 frame = frame_with_cursor;
158 }
159
160 callback_->OnCaptureCompleted(frame);
161 }
162
OnMouseCursor(MouseCursor * cursor)163 void DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) {
164 cursor_.reset(cursor);
165 }
166
OnMouseCursorPosition(MouseCursorMonitor::CursorState state,const DesktopVector & position)167 void DesktopAndCursorComposer::OnMouseCursorPosition(
168 MouseCursorMonitor::CursorState state,
169 const DesktopVector& position) {
170 cursor_state_ = state;
171 cursor_position_ = position;
172 }
173
174 } // namespace webrtc
175