OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/desktop_capture/differ.h" | 11 #include "webrtc/modules/desktop_capture/differ.h" |
12 | 12 |
13 #include "string.h" | 13 #include "string.h" |
14 | 14 |
15 #include "webrtc/base/checks.h" | |
16 #include "webrtc/modules/desktop_capture/desktop_region.h" | |
17 #include "webrtc/modules/desktop_capture/desktop_geometry.h" | |
15 #include "webrtc/modules/desktop_capture/differ_block.h" | 18 #include "webrtc/modules/desktop_capture/differ_block.h" |
16 #include "webrtc/system_wrappers/include/logging.h" | 19 #include "webrtc/system_wrappers/include/logging.h" |
17 | 20 |
18 namespace webrtc { | 21 namespace webrtc { |
19 | 22 |
20 Differ::Differ(int width, int height, int bpp, int stride) { | 23 Differ::Differ(int width, int height, int bpp, int stride) : |
21 // Dimensions of screen. | 24 // Dimensions of screen. |
22 width_ = width; | 25 width_(width), |
23 height_ = height; | 26 height_(height), |
24 bytes_per_pixel_ = bpp; | 27 bytes_per_pixel_(bpp), |
25 bytes_per_row_ = stride; | 28 bytes_per_row_(stride), |
26 | 29 // Calc number of blocks (full and partial) required to cover entire image. |
27 // Calc number of blocks (full and partial) required to cover entire image. | 30 // One additional row/column is added as a boundary on the right & bottom. |
28 // One additional row/column is added as a boundary on the right & bottom. | 31 diff_info_width_(((width_ + kBlockSize - 1) / kBlockSize) + 1), |
29 diff_info_width_ = ((width_ + kBlockSize - 1) / kBlockSize) + 1; | 32 diff_info_height_(((height_ + kBlockSize - 1) / kBlockSize) + 1), |
30 diff_info_height_ = ((height_ + kBlockSize - 1) / kBlockSize) + 1; | 33 diff_info_size_(diff_info_width_ * diff_info_height_ * sizeof(bool)), |
31 diff_info_size_ = diff_info_width_ * diff_info_height_ * sizeof(bool); | 34 diff_info_(new bool[diff_info_size_]) {} |
32 diff_info_.reset(new bool[diff_info_size_]); | |
33 } | |
34 | 35 |
35 Differ::~Differ() {} | 36 Differ::~Differ() {} |
36 | 37 |
37 void Differ::CalcDirtyRegion(const uint8_t* prev_buffer, | 38 void Differ::CalcDirtyRegion(const uint8_t* prev_buffer, |
38 const uint8_t* curr_buffer, | 39 const uint8_t* curr_buffer, |
39 DesktopRegion* region) { | 40 DesktopRegion* region) { |
Jamie
2016/08/03 23:52:25
Maybe just call through to CalcDirtyRegionWithHint
Hzj_jie
2016/08/04 02:28:07
If you do not have concern with the unnecessary fo
| |
41 // Reset internal dirty state to false. | |
42 memset(diff_info_.get(), 0, diff_info_size_); | |
43 | |
40 // Identify all the blocks that contain changed pixels. | 44 // Identify all the blocks that contain changed pixels. |
41 MarkDirtyBlocks(prev_buffer, curr_buffer); | 45 MarkDirtyBlocks(prev_buffer, |
46 curr_buffer, | |
47 DesktopRect::MakeWH(width_, height_)); | |
48 | |
49 // Now that we've identified the blocks that have changed, merge adjacent | |
50 // blocks to minimize the number of rects that we return. | |
51 MergeBlocks(region); | |
52 } | |
53 | |
54 void Differ::CalcDirtyRegionWithHints(const uint8_t* prev_buffer, | |
55 const uint8_t* curr_buffer, | |
56 const DesktopRegion& hints, | |
57 DesktopRegion* region) { | |
58 // Reset internal dirty state to false. | |
59 memset(diff_info_.get(), 0, diff_info_size_); | |
60 | |
61 // Identify all the blocks that contain changed pixels. | |
62 for (auto it = DesktopRegion::Iterator(hints); | |
63 !it.IsAtEnd(); | |
64 it.Advance()) { | |
65 MarkDirtyBlocks(prev_buffer, curr_buffer, it.rect()); | |
66 } | |
42 | 67 |
43 // Now that we've identified the blocks that have changed, merge adjacent | 68 // Now that we've identified the blocks that have changed, merge adjacent |
44 // blocks to minimize the number of rects that we return. | 69 // blocks to minimize the number of rects that we return. |
45 MergeBlocks(region); | 70 MergeBlocks(region); |
46 } | 71 } |
47 | 72 |
48 void Differ::MarkDirtyBlocks(const uint8_t* prev_buffer, | 73 void Differ::MarkDirtyBlocks(const uint8_t* prev_buffer, |
49 const uint8_t* curr_buffer) { | 74 const uint8_t* curr_buffer, |
50 memset(diff_info_.get(), 0, diff_info_size_); | 75 const DesktopRect& rect) { |
76 RTC_DCHECK(rect.width() <= width_); | |
77 RTC_DCHECK(rect.height() <= height_); | |
51 | 78 |
52 // Calc number of full blocks. | 79 if (rect.is_empty()) { |
53 int x_full_blocks = width_ / kBlockSize; | 80 return; |
54 int y_full_blocks = height_ / kBlockSize; | 81 } |
82 | |
83 // Calculate the range of blocks. | |
Jamie
2016/08/03 23:52:25
Since right and bottom are both past-the-end point
Hzj_jie
2016/08/04 02:28:07
This seems not correct to me,
Case 1: considering
| |
84 int x_start = rect.left() / kBlockSize; | |
85 int y_start = rect.top() / kBlockSize; | |
86 int x_end = (rect.right() + kBlockSize - 1) / kBlockSize; | |
87 int y_end = (rect.bottom() + kBlockSize - 1) / kBlockSize; | |
88 if (x_end * kBlockSize > width_) { | |
89 x_end--; | |
90 } | |
91 if (y_end * kBlockSize > height_) { | |
92 y_end--; | |
93 } | |
55 | 94 |
56 // Calc size of partial blocks which may be present on right and bottom edge. | 95 // Calc size of partial blocks which may be present on right and bottom edge. |
57 int partial_column_width = width_ - (x_full_blocks * kBlockSize); | 96 int partial_column_width = rect.right() - (x_end * kBlockSize); |
58 int partial_row_height = height_ - (y_full_blocks * kBlockSize); | 97 int partial_row_height = rect.bottom() - (y_end * kBlockSize); |
59 | 98 |
60 // Offset from the start of one block-column to the next. | 99 // Offset from the start of one block-column to the next. |
61 int block_x_offset = bytes_per_pixel_ * kBlockSize; | 100 int block_x_offset = bytes_per_pixel_ * kBlockSize; |
62 // Offset from the start of one block-row to the next. | 101 // Offset from the start of one block-row to the next. |
63 int block_y_stride = (width_ * bytes_per_pixel_) * kBlockSize; | 102 int block_y_stride = (width_ * bytes_per_pixel_) * kBlockSize; |
64 // Offset from the start of one diff_info row to the next. | 103 // Offset from the start of one diff_info row to the next. |
65 int diff_info_stride = diff_info_width_ * sizeof(bool); | 104 int diff_info_stride = diff_info_width_ * sizeof(bool); |
66 | 105 |
67 const uint8_t* prev_block_row_start = prev_buffer; | 106 const uint8_t* prev_block_row_start = |
68 const uint8_t* curr_block_row_start = curr_buffer; | 107 prev_buffer + y_start * block_y_stride + x_start * block_x_offset; |
69 bool* diff_info_row_start = diff_info_.get(); | 108 const uint8_t* curr_block_row_start = |
109 curr_buffer + (prev_block_row_start - prev_buffer); | |
110 bool* diff_info_row_start = | |
111 diff_info_.get() + y_start * diff_info_width_ + x_start; | |
70 | 112 |
71 for (int y = 0; y < y_full_blocks; y++) { | 113 for (int y = y_start; y < y_end; y++) { |
72 const uint8_t* prev_block = prev_block_row_start; | 114 const uint8_t* prev_block = prev_block_row_start; |
73 const uint8_t* curr_block = curr_block_row_start; | 115 const uint8_t* curr_block = curr_block_row_start; |
74 bool* diff_info = diff_info_row_start; | 116 bool* diff_info = diff_info_row_start; |
75 | 117 |
76 for (int x = 0; x < x_full_blocks; x++) { | 118 for (int x = x_start; x < x_end; x++) { |
77 // Mark this block as being modified so that it gets incorporated into | 119 // Mark this block as being modified so that it gets incorporated into |
78 // a dirty rect. | 120 // a dirty rect. |
79 *diff_info = BlockDifference(prev_block, curr_block, bytes_per_row_); | 121 *diff_info = BlockDifference(prev_block, curr_block, bytes_per_row_); |
80 prev_block += block_x_offset; | 122 prev_block += block_x_offset; |
81 curr_block += block_x_offset; | 123 curr_block += block_x_offset; |
82 diff_info += sizeof(bool); | 124 diff_info += sizeof(bool); |
Jamie
2016/08/03 23:52:25
This should just be diff_info++, I think, since po
Hzj_jie
2016/08/04 02:28:07
Oh, I have not noticed these lines (and three line
| |
83 } | 125 } |
84 | 126 |
85 // If there is a partial column at the end, handle it. | 127 // If there is a partial column at the end, handle it. |
86 // This condition should rarely, if ever, occur. | 128 // This condition should rarely, if ever, occur. |
Jamie
2016/08/03 23:52:25
I suspect this is no longer true; it's rare when t
Hzj_jie
2016/08/04 02:28:06
We always try our best to cover the damage rectang
| |
87 if (partial_column_width != 0) { | 129 if (partial_column_width > 0) { |
88 *diff_info = !PartialBlocksEqual(prev_block, curr_block, bytes_per_row_, | 130 *diff_info = !PartialBlocksEqual(prev_block, curr_block, bytes_per_row_, |
89 partial_column_width, kBlockSize); | 131 partial_column_width, kBlockSize); |
90 diff_info += sizeof(bool); | 132 diff_info += sizeof(bool); |
91 } | 133 } |
92 | 134 |
93 // Update pointers for next row. | 135 // Update pointers for next row. |
94 prev_block_row_start += block_y_stride; | 136 prev_block_row_start += block_y_stride; |
95 curr_block_row_start += block_y_stride; | 137 curr_block_row_start += block_y_stride; |
96 diff_info_row_start += diff_info_stride; | 138 diff_info_row_start += diff_info_stride; |
97 } | 139 } |
98 | 140 |
99 // If the screen height is not a multiple of the block size, then this | 141 // If the screen height is not a multiple of the block size, then this |
100 // handles the last partial row. This situation is far more common than the | 142 // handles the last partial row. This situation is far more common than the |
101 // 'partial column' case. | 143 // 'partial column' case. |
Jamie
2016/08/03 23:52:25
As above, this second sentence can be removed now.
Hzj_jie
2016/08/04 02:28:06
Done.
| |
102 if (partial_row_height != 0) { | 144 if (partial_row_height > 0) { |
103 const uint8_t* prev_block = prev_block_row_start; | 145 const uint8_t* prev_block = prev_block_row_start; |
104 const uint8_t* curr_block = curr_block_row_start; | 146 const uint8_t* curr_block = curr_block_row_start; |
105 bool* diff_info = diff_info_row_start; | 147 bool* diff_info = diff_info_row_start; |
106 for (int x = 0; x < x_full_blocks; x++) { | 148 for (int x = x_start; x < x_end; x++) { |
107 *diff_info = !PartialBlocksEqual(prev_block, curr_block, | 149 *diff_info = !PartialBlocksEqual(prev_block, curr_block, bytes_per_row_, |
108 bytes_per_row_, | |
109 kBlockSize, partial_row_height); | 150 kBlockSize, partial_row_height); |
110 prev_block += block_x_offset; | 151 prev_block += block_x_offset; |
111 curr_block += block_x_offset; | 152 curr_block += block_x_offset; |
112 diff_info += sizeof(bool); | 153 diff_info += sizeof(bool); |
113 } | 154 } |
114 if (partial_column_width != 0) { | 155 if (partial_column_width > 0) { |
115 *diff_info = !PartialBlocksEqual(prev_block, curr_block, bytes_per_row_, | 156 *diff_info = !PartialBlocksEqual(prev_block, curr_block, bytes_per_row_, |
116 partial_column_width, | 157 partial_column_width, |
117 partial_row_height); | 158 partial_row_height); |
118 diff_info += sizeof(bool); | 159 diff_info += sizeof(bool); |
119 } | 160 } |
120 } | 161 } |
121 } | 162 } |
122 | 163 |
123 bool Differ::PartialBlocksEqual(const uint8_t* prev_buffer, | 164 bool Differ::PartialBlocksEqual(const uint8_t* prev_buffer, |
124 const uint8_t* curr_buffer, | 165 const uint8_t* curr_buffer, |
125 int stride, int width, int height) { | 166 int stride, int width, int height) { |
167 RTC_DCHECK(width > 0 && height > 0); | |
126 int width_bytes = width * bytes_per_pixel_; | 168 int width_bytes = width * bytes_per_pixel_; |
127 for (int y = 0; y < height; y++) { | 169 for (int y = 0; y < height; y++) { |
128 if (memcmp(prev_buffer, curr_buffer, width_bytes) != 0) | 170 if (memcmp(prev_buffer, curr_buffer, width_bytes) != 0) |
129 return false; | 171 return false; |
130 prev_buffer += bytes_per_row_; | 172 prev_buffer += bytes_per_row_; |
131 curr_buffer += bytes_per_row_; | 173 curr_buffer += bytes_per_row_; |
132 } | 174 } |
133 return true; | 175 return true; |
134 } | 176 } |
135 | 177 |
136 void Differ::MergeBlocks(DesktopRegion* region) { | 178 void Differ::MergeBlocks(DesktopRegion* region) const { |
137 region->Clear(); | 179 region->Clear(); |
138 | 180 |
139 bool* diff_info_row_start = diff_info_.get(); | 181 bool* diff_info_row_start = diff_info_.get(); |
140 int diff_info_stride = diff_info_width_ * sizeof(bool); | 182 int diff_info_stride = diff_info_width_ * sizeof(bool); |
141 | 183 |
142 for (int y = 0; y < diff_info_height_; y++) { | 184 for (int y = 0; y < diff_info_height_; y++) { |
143 bool* diff_info = diff_info_row_start; | 185 bool* diff_info = diff_info_row_start; |
144 for (int x = 0; x < diff_info_width_; x++) { | 186 for (int x = 0; x < diff_info_width_; x++) { |
145 if (*diff_info) { | 187 if (*diff_info) { |
146 // We've found a modified block. Look at blocks to the right and below | 188 // We've found a modified block. Look at blocks to the right and below |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
202 // Increment to next block in this row. | 244 // Increment to next block in this row. |
203 diff_info++; | 245 diff_info++; |
204 } | 246 } |
205 | 247 |
206 // Go to start of next row. | 248 // Go to start of next row. |
207 diff_info_row_start += diff_info_stride; | 249 diff_info_row_start += diff_info_stride; |
208 } | 250 } |
209 } | 251 } |
210 | 252 |
211 } // namespace webrtc | 253 } // namespace webrtc |
OLD | NEW |