mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00

Bug: webrtc:12338 Change-Id: I300ba78fc4423db7030e555d7e51d2cb2246e9a4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/227162 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Artem Titov <titovartem@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34678}
184 lines
6.2 KiB
C++
184 lines
6.2 KiB
C++
/*
|
|
* Copyright (c) 2016 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_generator.h"
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include <memory>
|
|
|
|
#include "modules/desktop_capture/rgba_color.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/random.h"
|
|
#include "rtc_base/time_utils.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
// Sets `updated_region` to `frame`. If `enlarge_updated_region` is
|
|
// true, this function will randomly enlarge each DesktopRect in
|
|
// `updated_region`. But the enlarged DesktopRegion won't excceed the
|
|
// frame->size(). If `add_random_updated_region` is true, several random
|
|
// rectangles will also be included in `frame`.
|
|
void SetUpdatedRegion(DesktopFrame* frame,
|
|
const DesktopRegion& updated_region,
|
|
bool enlarge_updated_region,
|
|
int enlarge_range,
|
|
bool add_random_updated_region) {
|
|
const DesktopRect screen_rect = DesktopRect::MakeSize(frame->size());
|
|
Random random(rtc::TimeMicros());
|
|
frame->mutable_updated_region()->Clear();
|
|
for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd();
|
|
it.Advance()) {
|
|
DesktopRect rect = it.rect();
|
|
if (enlarge_updated_region && enlarge_range > 0) {
|
|
rect.Extend(random.Rand(enlarge_range), random.Rand(enlarge_range),
|
|
random.Rand(enlarge_range), random.Rand(enlarge_range));
|
|
rect.IntersectWith(screen_rect);
|
|
}
|
|
frame->mutable_updated_region()->AddRect(rect);
|
|
}
|
|
|
|
if (add_random_updated_region) {
|
|
for (int i = random.Rand(10); i >= 0; i--) {
|
|
// At least a 1 x 1 updated region.
|
|
const int left = random.Rand(0, frame->size().width() - 2);
|
|
const int top = random.Rand(0, frame->size().height() - 2);
|
|
const int right = random.Rand(left + 1, frame->size().width());
|
|
const int bottom = random.Rand(top + 1, frame->size().height());
|
|
frame->mutable_updated_region()->AddRect(
|
|
DesktopRect::MakeLTRB(left, top, right, bottom));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Paints pixels in `rect` of `frame` to `color`.
|
|
void PaintRect(DesktopFrame* frame, DesktopRect rect, RgbaColor rgba_color) {
|
|
static_assert(DesktopFrame::kBytesPerPixel == sizeof(uint32_t),
|
|
"kBytesPerPixel should be 4.");
|
|
RTC_DCHECK_GE(frame->size().width(), rect.right());
|
|
RTC_DCHECK_GE(frame->size().height(), rect.bottom());
|
|
uint32_t color = rgba_color.ToUInt32();
|
|
uint8_t* row = frame->GetFrameDataAtPos(rect.top_left());
|
|
for (int i = 0; i < rect.height(); i++) {
|
|
uint32_t* column = reinterpret_cast<uint32_t*>(row);
|
|
for (int j = 0; j < rect.width(); j++) {
|
|
column[j] = color;
|
|
}
|
|
row += frame->stride();
|
|
}
|
|
}
|
|
|
|
// Paints pixels in `region` of `frame` to `color`.
|
|
void PaintRegion(DesktopFrame* frame,
|
|
DesktopRegion* region,
|
|
RgbaColor rgba_color) {
|
|
region->IntersectWith(DesktopRect::MakeSize(frame->size()));
|
|
for (DesktopRegion::Iterator it(*region); !it.IsAtEnd(); it.Advance()) {
|
|
PaintRect(frame, it.rect(), rgba_color);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
DesktopFrameGenerator::DesktopFrameGenerator() {}
|
|
DesktopFrameGenerator::~DesktopFrameGenerator() {}
|
|
|
|
DesktopFramePainter::DesktopFramePainter() {}
|
|
DesktopFramePainter::~DesktopFramePainter() {}
|
|
|
|
PainterDesktopFrameGenerator::PainterDesktopFrameGenerator()
|
|
: size_(1024, 768),
|
|
return_frame_(true),
|
|
provide_updated_region_hints_(false),
|
|
enlarge_updated_region_(false),
|
|
enlarge_range_(20),
|
|
add_random_updated_region_(false),
|
|
painter_(nullptr) {}
|
|
PainterDesktopFrameGenerator::~PainterDesktopFrameGenerator() {}
|
|
|
|
std::unique_ptr<DesktopFrame> PainterDesktopFrameGenerator::GetNextFrame(
|
|
SharedMemoryFactory* factory) {
|
|
if (!return_frame_) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::unique_ptr<DesktopFrame> frame = std::unique_ptr<DesktopFrame>(
|
|
factory ? SharedMemoryDesktopFrame::Create(size_, factory).release()
|
|
: new BasicDesktopFrame(size_));
|
|
if (painter_) {
|
|
DesktopRegion updated_region;
|
|
if (!painter_->Paint(frame.get(), &updated_region)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (provide_updated_region_hints_) {
|
|
SetUpdatedRegion(frame.get(), updated_region, enlarge_updated_region_,
|
|
enlarge_range_, add_random_updated_region_);
|
|
} else {
|
|
frame->mutable_updated_region()->SetRect(
|
|
DesktopRect::MakeSize(frame->size()));
|
|
}
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
|
|
DesktopSize* PainterDesktopFrameGenerator::size() {
|
|
return &size_;
|
|
}
|
|
|
|
void PainterDesktopFrameGenerator::set_return_frame(bool return_frame) {
|
|
return_frame_ = return_frame;
|
|
}
|
|
|
|
void PainterDesktopFrameGenerator::set_provide_updated_region_hints(
|
|
bool provide_updated_region_hints) {
|
|
provide_updated_region_hints_ = provide_updated_region_hints;
|
|
}
|
|
|
|
void PainterDesktopFrameGenerator::set_enlarge_updated_region(
|
|
bool enlarge_updated_region) {
|
|
enlarge_updated_region_ = enlarge_updated_region;
|
|
}
|
|
|
|
void PainterDesktopFrameGenerator::set_enlarge_range(int enlarge_range) {
|
|
enlarge_range_ = enlarge_range;
|
|
}
|
|
|
|
void PainterDesktopFrameGenerator::set_add_random_updated_region(
|
|
bool add_random_updated_region) {
|
|
add_random_updated_region_ = add_random_updated_region;
|
|
}
|
|
|
|
void PainterDesktopFrameGenerator::set_desktop_frame_painter(
|
|
DesktopFramePainter* painter) {
|
|
painter_ = painter;
|
|
}
|
|
|
|
BlackWhiteDesktopFramePainter::BlackWhiteDesktopFramePainter() {}
|
|
BlackWhiteDesktopFramePainter::~BlackWhiteDesktopFramePainter() {}
|
|
|
|
DesktopRegion* BlackWhiteDesktopFramePainter::updated_region() {
|
|
return &updated_region_;
|
|
}
|
|
|
|
bool BlackWhiteDesktopFramePainter::Paint(DesktopFrame* frame,
|
|
DesktopRegion* updated_region) {
|
|
RTC_DCHECK(updated_region->is_empty());
|
|
memset(frame->data(), 0, frame->stride() * frame->size().height());
|
|
PaintRegion(frame, &updated_region_, RgbaColor(0xFFFFFFFF));
|
|
updated_region_.Swap(updated_region);
|
|
return true;
|
|
}
|
|
|
|
} // namespace webrtc
|