Chromium Code Reviews| 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 |