blob: 3141fee8da24abdd54373fbc8f39f450801b3073 [file] [log] [blame]
/*
* 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