Chromium Code Reviews| Index: webrtc/modules/desktop_capture/desktop_frame_generator.cc |
| diff --git a/webrtc/modules/desktop_capture/desktop_frame_generator.cc b/webrtc/modules/desktop_capture/desktop_frame_generator.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..32ec3f4d92c1035a0ebf40429ac6c2fad157bb7e |
| --- /dev/null |
| +++ b/webrtc/modules/desktop_capture/desktop_frame_generator.cc |
| @@ -0,0 +1,168 @@ |
| +/* |
| + * 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 "webrtc/modules/desktop_capture/desktop_frame_generator.h" |
| + |
| +#include <stdint.h> |
| +#include <string.h> |
| + |
| +#include <memory> |
| + |
| +#include "webrtc/base/random.h" |
| +#include "webrtc/base/timeutils.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 = DesktopRect::MakeLTRB(rect.left() - random.Rand(enlarge_range), |
| + rect.top() - random.Rand(enlarge_range), |
| + rect.right() + random.Rand(enlarge_range), |
| + rect.bottom() + random.Rand(enlarge_range)); |
|
Sergey Ulanov
2016/08/18 05:07:58
There are several other places where we need the s
Hzj_jie
2016/08/23 00:54:58
Done.
|
| + 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, uint32_t color) { |
| + static_assert(DesktopFrame::kBytesPerPixel == sizeof(uint32_t), |
| + "kBytesPerPixel should be 4."); |
| + RTC_DCHECK(frame->size().width() >= rect.right() && |
| + frame->size().height() >= rect.bottom()); |
| + int row = rect.top() * frame->stride(); |
| + for (int i = 0; i < rect.height(); i++) { |
| + int column = rect.left() * DesktopFrame::kBytesPerPixel; |
| + for (int j = 0; j < rect.width(); j++) { |
| + memcpy(&frame->data()[row + column], &color, sizeof(color)); |
|
Sergey Ulanov
2016/08/18 05:07:58
Instead of calling memcpy() for every pixel it wou
Hzj_jie
2016/08/23 00:54:58
Done.
Hzj_jie
2016/08/25 18:20:12
Seems both memcpy and uint32_t assignment will be
Sergey Ulanov
2016/09/01 19:27:56
Simple assignment will still be faster and clearer
Hzj_jie
2016/09/01 23:26:42
Yes, it will have a ToUInt32() function to handle
|
| + column += DesktopFrame::kBytesPerPixel; |
| + } |
| + row += frame->stride(); |
| + } |
| +} |
| + |
| +// Paints pixels in |region| of |frame| to |color|. |
| +void PaintRegion(DesktopFrame* frame, DesktopRegion* region, uint32_t color) { |
| + region->IntersectWith(DesktopRect::MakeSize(frame->size())); |
| + for (DesktopRegion::Iterator it(*region); !it.IsAtEnd(); it.Advance()) { |
| + PaintRect(frame, it.rect(), color); |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +DesktopFrameGenerator::DesktopFrameGenerator() {} |
| +DesktopFrameGenerator::~DesktopFrameGenerator() {} |
| + |
| +BaseDesktopFrameGenerator::BaseDesktopFrameGenerator() |
| + : size_(1024, 768), |
| + return_frame_(true), |
| + provide_updated_region_hints_(false), |
| + enlarge_updated_region_(false), |
| + enlarge_range_(20), |
| + add_random_updated_region_(false) {} |
| +BaseDesktopFrameGenerator::~BaseDesktopFrameGenerator() {} |
| + |
| +std::unique_ptr<DesktopFrame> BaseDesktopFrameGenerator::operator()( |
| + SharedMemoryFactory* factory) { |
| + if (return_frame_) { |
| + std::unique_ptr<DesktopFrame> frame = std::unique_ptr<DesktopFrame>( |
| + factory ? SharedMemoryDesktopFrame::Create(size_, factory).release() |
| + : new BasicDesktopFrame(size_)); |
| + DesktopRegion updated_region; |
| + if (!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_); |
| + } |
| + return frame; |
| + } else { |
|
Sergey Ulanov
2016/08/18 05:07:58
Don't use else after return. Best to move the !ret
Hzj_jie
2016/08/23 00:54:58
Done.
|
| + return nullptr; |
| + } |
| +} |
| + |
| +DesktopSize* BaseDesktopFrameGenerator::size() { |
| + return &size_; |
| +} |
| + |
| +void BaseDesktopFrameGenerator::set_return_frame(bool return_frame) { |
| + return_frame_ = return_frame; |
| +} |
| + |
| +void BaseDesktopFrameGenerator::set_provide_updated_region_hints( |
| + bool provide_updated_region_hints) { |
| + provide_updated_region_hints_ = provide_updated_region_hints; |
| +} |
| + |
| +void BaseDesktopFrameGenerator::set_enlarge_updated_region( |
| + bool enlarge_updated_region) { |
| + enlarge_updated_region_ = enlarge_updated_region; |
| +} |
| + |
| +void BaseDesktopFrameGenerator::set_enlarge_range(int enlarge_range) { |
| + enlarge_range_ = enlarge_range; |
| +} |
| + |
| +void BaseDesktopFrameGenerator::set_add_random_updated_region( |
| + bool add_random_updated_region) { |
| + add_random_updated_region_ = add_random_updated_region; |
| +} |
| + |
| +BlackWhiteDesktopFrameGenerator::BlackWhiteDesktopFrameGenerator() {} |
| +BlackWhiteDesktopFrameGenerator::~BlackWhiteDesktopFrameGenerator() {} |
| + |
| +DesktopRegion* BlackWhiteDesktopFrameGenerator::updated_region() { |
| + return &updated_region_; |
| +} |
| + |
| +bool BlackWhiteDesktopFrameGenerator::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_, UINT32_MAX); |
| + updated_region_.Swap(updated_region); |
| + return true; |
| +} |
| + |
| +} // namespace webrtc |