Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(944)

Side by Side Diff: webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.cc

Issue 2202443002: [WebRTC] Add ScreenCapturerDifferWrapper to share Differ across ScreenCapturers (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Resolve review comments Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h"
12
13 #include <algorithm>
14 #include <utility>
15
16 #include "webrtc/base/checks.h"
17 #include "webrtc/base/timeutils.h"
18 #include "webrtc/modules/desktop_capture/desktop_geometry.h"
19 #include "webrtc/modules/desktop_capture/differ_block.h"
20
21 namespace webrtc {
22
23 namespace {
24
25 static const int kBlockXOffset = kBlockSize * DesktopFrame::kBytesPerPixel;
26
27 // Returns true if (0, 0) - (|width|, |height|) vector in |old_buffer| and
28 // |new_buffer| are equal. |width| should be less than 32
29 // (defined by kBlockSize), otherwise BlockDifference() should be used.
30 bool PartialBlockDifference(const uint8_t* old_buffer,
31 const uint8_t* new_buffer,
32 int width,
33 int height,
34 int stride) {
35 RTC_DCHECK(width < kBlockSize);
36 const int width_bytes = width * DesktopFrame::kBytesPerPixel;
37 for (int i = 0; i < height; i++) {
38 if (memcmp(old_buffer, new_buffer, width_bytes) != 0) {
39 return true;
40 }
41 old_buffer += stride;
42 new_buffer += stride;
43 }
44 return false;
45 }
46
47 // Compares block-columns in the range of [0, |x_end| - |x_start|), in
48 // a row in the range of [row_top, row_top + row_height), starts from
49 // |old_buffer| and |new_buffer|, and outputs updated regions into |output|.
50 // |width| is the DesktopFrame::size()::width(), |stride| is the
51 // DesktopFrame::stride().
52 void CompareRow(const uint8_t* old_buffer,
53 const uint8_t* new_buffer,
54 const int x_start,
55 const int x_end,
56 const int row_top,
57 const int row_height,
58 const int width,
59 const int stride,
60 DesktopRegion* const output) {
61 const int row_bottom = row_top + row_height;
62 const int column_right = std::min(x_end * kBlockSize, width);
63
64 // The first block-column in a continuous dirty area in current block-row.
65 int first_dirty_x_block = -1;
66
67 // We always need to add dirty area into |output| in the last block, so handle
68 // it separatedly.
69 for (int x = x_start; x < x_end - 1; x++) {
70 if (BlockDifference(old_buffer, new_buffer, row_height, stride)) {
71 if (first_dirty_x_block == -1) {
72 // This is the first dirty block in a continuous dirty area.
73 first_dirty_x_block = x;
74 }
75 } else if (first_dirty_x_block != -1) {
76 // The block on the left is the last dirty block in a continuous
77 // dirty area.
78 output->AddRect(DesktopRect::MakeLTRB(first_dirty_x_block * kBlockSize,
79 row_top, x * kBlockSize,
80 row_bottom));
81 first_dirty_x_block = -1;
82 }
83 old_buffer += kBlockXOffset;
84 new_buffer += kBlockXOffset;
85 }
86
87 bool last_block_diff;
88 if (x_end * kBlockSize > width) {
89 // The last one is a partial vector.
90 last_block_diff = PartialBlockDifference(
91 old_buffer, new_buffer, column_right - (x_end - 1) * kBlockSize,
92 row_height, stride);
93 } else {
94 last_block_diff = BlockDifference(
95 old_buffer, new_buffer, row_height, stride);
96 }
97 if (last_block_diff) {
98 if (first_dirty_x_block == -1) {
99 output->AddRect(DesktopRect::MakeLTRB((x_end - 1) * kBlockSize, row_top,
100 column_right, row_bottom));
101 } else {
102 output->AddRect(DesktopRect::MakeLTRB(first_dirty_x_block * kBlockSize,
103 row_top, column_right, row_bottom));
104 }
105 } else if (first_dirty_x_block != -1) {
106 output->AddRect(DesktopRect::MakeLTRB(first_dirty_x_block * kBlockSize,
107 row_top, (x_end - 1) * kBlockSize,
108 row_bottom));
109 }
110 }
111
112 // Compares |rect| area in |old_frame| and |new_frame|, and outputs dirty
113 // regions into |output|.
114 void CompareFrames(const DesktopFrame& old_frame,
115 const DesktopFrame& new_frame,
116 DesktopRect rect,
117 DesktopRegion* const output) {
118 RTC_DCHECK(old_frame.size().equals(new_frame.size()));
119 RTC_DCHECK_EQ(old_frame.stride(), new_frame.stride());
120 rect.IntersectWith(DesktopRect::MakeSize(old_frame.size()));
121
122 const int x_start = rect.left() / kBlockSize;
123 const int y_start = rect.top() / kBlockSize;
124 const int x_end = (rect.right() + kBlockSize - 1) / kBlockSize;
125 const int y_end = (rect.bottom() + kBlockSize - 1) / kBlockSize;
126 const DesktopVector block_top_left(x_start * kBlockSize,
127 y_start * kBlockSize);
128 // Offset from the start of one block-row to the next.
129 const int block_y_stride = old_frame.stride() * kBlockSize;
130 const uint8_t* prev_block_row_start =
131 old_frame.GetFrameDataAtPos(block_top_left);
132 const uint8_t* curr_block_row_start =
133 new_frame.GetFrameDataAtPos(block_top_left);
134
135 int row_top = y_start * kBlockSize;
136 // The last row may have a different height, so we handle it separately.
137 for (int y = y_start; y < y_end - 1; y++) {
138 CompareRow(prev_block_row_start, curr_block_row_start, x_start, x_end,
Sergey Ulanov 2016/08/18 05:07:58 This function compares whole 32x32 blocks and as f
Hzj_jie 2016/08/18 08:50:31 Yes, I aware this issue, as this is a disadvantage
Hzj_jie 2016/08/23 00:54:59 After reducing the range of several random values
139 row_top, kBlockSize, old_frame.size().width(),
140 old_frame.stride(), output);
141 row_top += kBlockSize;
142 prev_block_row_start += block_y_stride;
143 curr_block_row_start += block_y_stride;
144 }
145 CompareRow(prev_block_row_start, curr_block_row_start, x_start, x_end,
146 row_top,
147 std::min(kBlockSize,
148 old_frame.size().height() - (y_end - 1) * kBlockSize),
149 old_frame.size().width(), old_frame.stride(), output);
150 }
151
152 } // namespace
153
154 ScreenCapturerDifferWrapper::ScreenCapturerDifferWrapper(
155 std::unique_ptr<ScreenCapturer> base_capturer,
156 bool diff_entire_frame)
157 : base_capturer_(std::move(base_capturer)),
158 diff_entire_frame_(diff_entire_frame) {
159 RTC_DCHECK(base_capturer_);
160 }
161
162 ScreenCapturerDifferWrapper::~ScreenCapturerDifferWrapper() {}
163
164 void ScreenCapturerDifferWrapper::Start(DesktopCapturer::Callback* callback) {
165 callback_ = callback;
166 base_capturer_->Start(this);
167 }
168
169 void ScreenCapturerDifferWrapper::SetSharedMemoryFactory(
170 std::unique_ptr<SharedMemoryFactory> shared_memory_factory) {
171 base_capturer_->SetSharedMemoryFactory(std::move(shared_memory_factory));
172 }
173
174 void ScreenCapturerDifferWrapper::Capture(const DesktopRegion& region) {
175 base_capturer_->Capture(region);
176 }
177
178 bool ScreenCapturerDifferWrapper::GetScreenList(ScreenList* screens) {
179 return base_capturer_->GetScreenList(screens);
180 }
181
182 bool ScreenCapturerDifferWrapper::SelectScreen(ScreenId id) {
183 return base_capturer_->SelectScreen(id);
184 }
185
186 void ScreenCapturerDifferWrapper::OnCaptureResult(
187 Result result,
188 std::unique_ptr<DesktopFrame> input_frame) {
189 int64_t start_time_nanos = rtc::TimeNanos();
190 if (!input_frame) {
191 callback_->OnCaptureResult(result, nullptr);
192 return;
193 }
194
195 std::unique_ptr<SharedDesktopFrame> frame =
196 SharedDesktopFrame::Wrap(std::move(input_frame));
197 if (result == Result::SUCCESS) {
198 if (last_frame_ &&
199 (last_frame_->size().width() != frame->size().width() ||
200 last_frame_->size().height() != frame->size().height() ||
201 last_frame_->stride() != frame->stride())) {
202 last_frame_.reset();
203 }
204
205 if (last_frame_) {
206 if (diff_entire_frame_) {
207 CompareFrames(*last_frame_, *frame,
208 DesktopRect::MakeSize(frame->size()),
209 frame->mutable_updated_region());
210 } else {
211 DesktopRegion hints;
212 hints.Swap(frame->GetUnderlyingFrame()->mutable_updated_region());
213 for (DesktopRegion::Iterator it(hints); !it.IsAtEnd(); it.Advance()) {
214 // Note, here we always expect the underlying capturer won't return a
215 // dirty region which excceeds the DesktopFrame::size().
216 CompareFrames(*last_frame_, *frame, it.rect(),
217 frame->mutable_updated_region());
218 }
219 }
220 } else {
221 frame->mutable_updated_region()->SetRect(
222 DesktopRect::MakeSize(frame->size()));
223 }
224 last_frame_ = frame->Share();
225 } else {
226 last_frame_.reset();
227 }
228
229 frame->set_capture_time_ms(frame->GetUnderlyingFrame()->capture_time_ms() +
Sergey Ulanov 2016/08/18 05:07:58 don't really need ->GetUnderlyingFrame(). The valu
Hzj_jie 2016/08/23 00:54:59 This SharedDesktopFrame is generated above @ line
230 (rtc::TimeNanos() - start_time_nanos) /
231 rtc::kNumNanosecsPerMillisec);
232 callback_->OnCaptureResult(result, std::move(frame));
233 }
234
235 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698