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 |