/* * 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 "modules/desktop_capture/desktop_frame.h" #include #include #include #include #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_geometry.h" #include "rtc_base/checks.h" #include "third_party/libyuv/include/libyuv/planar_functions.h" namespace webrtc { DesktopFrame::DesktopFrame(DesktopSize size, int stride, uint8_t* data, SharedMemory* shared_memory) : data_(data), shared_memory_(shared_memory), size_(size), stride_(stride), capture_time_ms_(0), capturer_id_(DesktopCapturerId::kUnknown) { RTC_DCHECK(size_.width() >= 0); RTC_DCHECK(size_.height() >= 0); } DesktopFrame::~DesktopFrame() = default; void DesktopFrame::CopyPixelsFrom(const uint8_t* src_buffer, int src_stride, const DesktopRect& dest_rect) { RTC_CHECK(DesktopRect::MakeSize(size()).ContainsRect(dest_rect)); uint8_t* dest = GetFrameDataAtPos(dest_rect.top_left()); libyuv::CopyPlane(src_buffer, src_stride, dest, stride(), DesktopFrame::kBytesPerPixel * dest_rect.width(), dest_rect.height()); } void DesktopFrame::CopyPixelsFrom(const DesktopFrame& src_frame, const DesktopVector& src_pos, const DesktopRect& dest_rect) { RTC_CHECK(DesktopRect::MakeSize(src_frame.size()) .ContainsRect( DesktopRect::MakeOriginSize(src_pos, dest_rect.size()))); CopyPixelsFrom(src_frame.GetFrameDataAtPos(src_pos), src_frame.stride(), dest_rect); } bool DesktopFrame::CopyIntersectingPixelsFrom(const DesktopFrame& src_frame, double horizontal_scale, double vertical_scale) { const DesktopVector& origin = top_left(); const DesktopVector& src_frame_origin = src_frame.top_left(); DesktopVector src_frame_offset = src_frame_origin.subtract(origin); // Determine the intersection, first adjusting its origin to account for any // DPI scaling. DesktopRect intersection_rect = src_frame.rect(); if (horizontal_scale != 1.0 || vertical_scale != 1.0) { DesktopVector origin_adjustment( static_cast( std::round((horizontal_scale - 1.0) * src_frame_offset.x())), static_cast( std::round((vertical_scale - 1.0) * src_frame_offset.y()))); intersection_rect.Translate(origin_adjustment); src_frame_offset = src_frame_offset.add(origin_adjustment); } intersection_rect.IntersectWith(rect()); if (intersection_rect.is_empty()) { return false; } // Translate the intersection rect to be relative to the outer rect. intersection_rect.Translate(-origin.x(), -origin.y()); // Determine source position for the copy (offsets of outer frame from // source origin, if positive). int32_t src_pos_x = std::max(0, -src_frame_offset.x()); int32_t src_pos_y = std::max(0, -src_frame_offset.y()); CopyPixelsFrom(src_frame, DesktopVector(src_pos_x, src_pos_y), intersection_rect); return true; } DesktopRect DesktopFrame::rect() const { const float scale = scale_factor(); // Only scale the size. return DesktopRect::MakeXYWH(top_left().x(), top_left().y(), size().width() / scale, size().height() / scale); } float DesktopFrame::scale_factor() const { float scale = 1.0f; #if defined(WEBRTC_MAC) || defined(CHROMEOS) // At least on Windows the logical and physical pixel are the same // See http://crbug.com/948362. if (!dpi().is_zero() && dpi().x() == dpi().y()) scale = dpi().x() / kStandardDPI; #endif return scale; } uint8_t* DesktopFrame::GetFrameDataAtPos(const DesktopVector& pos) const { return data() + stride() * pos.y() + DesktopFrame::kBytesPerPixel * pos.x(); } void DesktopFrame::CopyFrameInfoFrom(const DesktopFrame& other) { set_dpi(other.dpi()); set_capture_time_ms(other.capture_time_ms()); set_capturer_id(other.capturer_id()); *mutable_updated_region() = other.updated_region(); set_top_left(other.top_left()); set_icc_profile(other.icc_profile()); } void DesktopFrame::MoveFrameInfoFrom(DesktopFrame* other) { set_dpi(other->dpi()); set_capture_time_ms(other->capture_time_ms()); set_capturer_id(other->capturer_id()); mutable_updated_region()->Swap(other->mutable_updated_region()); set_top_left(other->top_left()); set_icc_profile(other->icc_profile()); } BasicDesktopFrame::BasicDesktopFrame(DesktopSize size) : DesktopFrame(size, kBytesPerPixel * size.width(), new uint8_t[kBytesPerPixel * size.width() * size.height()](), nullptr) {} BasicDesktopFrame::~BasicDesktopFrame() { delete[] data_; } // static DesktopFrame* BasicDesktopFrame::CopyOf(const DesktopFrame& frame) { DesktopFrame* result = new BasicDesktopFrame(frame.size()); // TODO(crbug.com/1330019): Temporary workaround for a known libyuv crash when // the height or width is 0. Remove this once this change has been merged. if (frame.size().width() && frame.size().height()) { libyuv::CopyPlane(frame.data(), frame.stride(), result->data(), result->stride(), frame.size().width() * kBytesPerPixel, frame.size().height()); } result->CopyFrameInfoFrom(frame); return result; } // static std::unique_ptr SharedMemoryDesktopFrame::Create( DesktopSize size, SharedMemoryFactory* shared_memory_factory) { RTC_DCHECK(shared_memory_factory); size_t buffer_size = size.height() * size.width() * kBytesPerPixel; std::unique_ptr shared_memory = shared_memory_factory->CreateSharedMemory(buffer_size); if (!shared_memory) return nullptr; return std::make_unique( size, size.width() * kBytesPerPixel, std::move(shared_memory)); } SharedMemoryDesktopFrame::SharedMemoryDesktopFrame(DesktopSize size, int stride, SharedMemory* shared_memory) : DesktopFrame(size, stride, reinterpret_cast(shared_memory->data()), shared_memory) {} SharedMemoryDesktopFrame::SharedMemoryDesktopFrame( DesktopSize size, int stride, std::unique_ptr shared_memory) : SharedMemoryDesktopFrame(size, stride, shared_memory.release()) {} SharedMemoryDesktopFrame::~SharedMemoryDesktopFrame() { delete shared_memory_; } } // namespace webrtc