| /* |
| * 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 "webrtc/modules/desktop_capture/desktop_and_cursor_composer.h" |
| |
| #include <string.h> |
| |
| #include "webrtc/modules/desktop_capture/desktop_capturer.h" |
| #include "webrtc/modules/desktop_capture/desktop_frame.h" |
| #include "webrtc/modules/desktop_capture/mouse_cursor.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; |
| } |
| } |
| |
| } // namespace |
| |
| DesktopAndCursorComposer::DesktopAndCursorComposer( |
| DesktopCapturer* desktop_capturer, |
| MouseCursorMonitor* mouse_monitor) |
| : desktop_capturer_(desktop_capturer), |
| mouse_monitor_(mouse_monitor) { |
| } |
| |
| DesktopAndCursorComposer::~DesktopAndCursorComposer() {} |
| |
| void DesktopAndCursorComposer::Start(DesktopCapturer::Callback* callback) { |
| callback_ = callback; |
| if (mouse_monitor_.get()) |
| mouse_monitor_->Init(this, MouseCursorMonitor::SHAPE_AND_POSITION); |
| desktop_capturer_->Start(this); |
| } |
| |
| void DesktopAndCursorComposer::Capture(const DesktopRegion& region) { |
| if (mouse_monitor_.get()) |
| mouse_monitor_->Capture(); |
| desktop_capturer_->Capture(region); |
| } |
| |
| SharedMemory* DesktopAndCursorComposer::CreateSharedMemory(size_t size) { |
| return callback_->CreateSharedMemory(size); |
| } |
| |
| void DesktopAndCursorComposer::OnCaptureCompleted(DesktopFrame* frame) { |
| if (cursor_.get() && cursor_state_ == MouseCursorMonitor::INSIDE) { |
| DesktopVector image_pos = cursor_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(frame->size())); |
| DesktopVector origin_shift = target_rect.top_left().subtract(target_origin); |
| int cursor_width = cursor_->image().size().width(); |
| AlphaBlend(reinterpret_cast<uint8_t*>(frame->data()) + |
| target_rect.top() * frame->stride() + |
| target_rect.left() * DesktopFrame::kBytesPerPixel, |
| frame->stride(), |
| cursor_->image().data() + |
| (origin_shift.y() * cursor_width + origin_shift.x()) * |
| DesktopFrame::kBytesPerPixel, |
| cursor_width * DesktopFrame::kBytesPerPixel, |
| target_rect.size()); |
| } |
| |
| callback_->OnCaptureCompleted(frame); |
| } |
| |
| void DesktopAndCursorComposer::OnMouseCursor(MouseCursor* cursor) { |
| cursor_.reset(cursor); |
| } |
| |
| void DesktopAndCursorComposer::OnMouseCursorPosition( |
| MouseCursorMonitor::CursorState state, |
| const DesktopVector& position) { |
| cursor_state_ = state; |
| cursor_position_ = position; |
| } |
| |
| } // namespace webrtc |