• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   scoped_ptr<DesktopFrame> original_frame_;
66 
67   DesktopVector restore_position_;
68   scoped_ptr<DesktopFrame> restore_frame_;
69 
70   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