Chromium Code Reviews| Index: webrtc/modules/desktop_capture/differ.cc |
| diff --git a/webrtc/modules/desktop_capture/differ.cc b/webrtc/modules/desktop_capture/differ.cc |
| index 8140e612a1008c0359237904958779f9c4e795fe..9ddfe1b63c4891d133e4a70dbf067c30bdd9492a 100644 |
| --- a/webrtc/modules/desktop_capture/differ.cc |
| +++ b/webrtc/modules/desktop_capture/differ.cc |
| @@ -12,50 +12,89 @@ |
| #include "string.h" |
| +#include "webrtc/base/checks.h" |
| +#include "webrtc/modules/desktop_capture/desktop_region.h" |
| +#include "webrtc/modules/desktop_capture/desktop_geometry.h" |
| #include "webrtc/modules/desktop_capture/differ_block.h" |
| #include "webrtc/system_wrappers/include/logging.h" |
| namespace webrtc { |
| -Differ::Differ(int width, int height, int bpp, int stride) { |
| - // Dimensions of screen. |
| - width_ = width; |
| - height_ = height; |
| - bytes_per_pixel_ = bpp; |
| - bytes_per_row_ = stride; |
| - |
| - // Calc number of blocks (full and partial) required to cover entire image. |
| - // One additional row/column is added as a boundary on the right & bottom. |
| - diff_info_width_ = ((width_ + kBlockSize - 1) / kBlockSize) + 1; |
| - diff_info_height_ = ((height_ + kBlockSize - 1) / kBlockSize) + 1; |
| - diff_info_size_ = diff_info_width_ * diff_info_height_ * sizeof(bool); |
| - diff_info_.reset(new bool[diff_info_size_]); |
| -} |
| +Differ::Differ(int width, int height, int bpp, int stride) : |
| + // Dimensions of screen. |
| + width_(width), |
| + height_(height), |
| + bytes_per_pixel_(bpp), |
| + bytes_per_row_(stride), |
| + // Calc number of blocks (full and partial) required to cover entire image. |
| + // One additional row/column is added as a boundary on the right & bottom. |
| + diff_info_width_(((width_ + kBlockSize - 1) / kBlockSize) + 1), |
| + diff_info_height_(((height_ + kBlockSize - 1) / kBlockSize) + 1), |
| + diff_info_size_(diff_info_width_ * diff_info_height_ * sizeof(bool)), |
| + diff_info_(new bool[diff_info_size_]) {} |
| Differ::~Differ() {} |
| void Differ::CalcDirtyRegion(const uint8_t* prev_buffer, |
| const uint8_t* curr_buffer, |
| 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
|
| + // Reset internal dirty state to false. |
| + memset(diff_info_.get(), 0, diff_info_size_); |
| + |
| // Identify all the blocks that contain changed pixels. |
| - MarkDirtyBlocks(prev_buffer, curr_buffer); |
| + MarkDirtyBlocks(prev_buffer, |
| + curr_buffer, |
| + DesktopRect::MakeWH(width_, height_)); |
| // Now that we've identified the blocks that have changed, merge adjacent |
| // blocks to minimize the number of rects that we return. |
| MergeBlocks(region); |
| } |
| -void Differ::MarkDirtyBlocks(const uint8_t* prev_buffer, |
| - const uint8_t* curr_buffer) { |
| +void Differ::CalcDirtyRegionWithHints(const uint8_t* prev_buffer, |
| + const uint8_t* curr_buffer, |
| + const DesktopRegion& hints, |
| + DesktopRegion* region) { |
| + // Reset internal dirty state to false. |
| memset(diff_info_.get(), 0, diff_info_size_); |
| - // Calc number of full blocks. |
| - int x_full_blocks = width_ / kBlockSize; |
| - int y_full_blocks = height_ / kBlockSize; |
| + // Identify all the blocks that contain changed pixels. |
| + for (auto it = DesktopRegion::Iterator(hints); |
| + !it.IsAtEnd(); |
| + it.Advance()) { |
| + MarkDirtyBlocks(prev_buffer, curr_buffer, it.rect()); |
| + } |
| + |
| + // Now that we've identified the blocks that have changed, merge adjacent |
| + // blocks to minimize the number of rects that we return. |
| + MergeBlocks(region); |
| +} |
| + |
| +void Differ::MarkDirtyBlocks(const uint8_t* prev_buffer, |
| + const uint8_t* curr_buffer, |
| + const DesktopRect& rect) { |
| + RTC_DCHECK(rect.width() <= width_); |
| + RTC_DCHECK(rect.height() <= height_); |
| + |
| + if (rect.is_empty()) { |
| + return; |
| + } |
| + |
| + // 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
|
| + int x_start = rect.left() / kBlockSize; |
| + int y_start = rect.top() / kBlockSize; |
| + int x_end = (rect.right() + kBlockSize - 1) / kBlockSize; |
| + int y_end = (rect.bottom() + kBlockSize - 1) / kBlockSize; |
| + if (x_end * kBlockSize > width_) { |
| + x_end--; |
| + } |
| + if (y_end * kBlockSize > height_) { |
| + y_end--; |
| + } |
| // Calc size of partial blocks which may be present on right and bottom edge. |
| - int partial_column_width = width_ - (x_full_blocks * kBlockSize); |
| - int partial_row_height = height_ - (y_full_blocks * kBlockSize); |
| + int partial_column_width = rect.right() - (x_end * kBlockSize); |
| + int partial_row_height = rect.bottom() - (y_end * kBlockSize); |
| // Offset from the start of one block-column to the next. |
| int block_x_offset = bytes_per_pixel_ * kBlockSize; |
| @@ -64,16 +103,19 @@ void Differ::MarkDirtyBlocks(const uint8_t* prev_buffer, |
| // Offset from the start of one diff_info row to the next. |
| int diff_info_stride = diff_info_width_ * sizeof(bool); |
| - const uint8_t* prev_block_row_start = prev_buffer; |
| - const uint8_t* curr_block_row_start = curr_buffer; |
| - bool* diff_info_row_start = diff_info_.get(); |
| + const uint8_t* prev_block_row_start = |
| + prev_buffer + y_start * block_y_stride + x_start * block_x_offset; |
| + const uint8_t* curr_block_row_start = |
| + curr_buffer + (prev_block_row_start - prev_buffer); |
| + bool* diff_info_row_start = |
| + diff_info_.get() + y_start * diff_info_width_ + x_start; |
| - for (int y = 0; y < y_full_blocks; y++) { |
| + for (int y = y_start; y < y_end; y++) { |
| const uint8_t* prev_block = prev_block_row_start; |
| const uint8_t* curr_block = curr_block_row_start; |
| bool* diff_info = diff_info_row_start; |
| - for (int x = 0; x < x_full_blocks; x++) { |
| + for (int x = x_start; x < x_end; x++) { |
| // Mark this block as being modified so that it gets incorporated into |
| // a dirty rect. |
| *diff_info = BlockDifference(prev_block, curr_block, bytes_per_row_); |
| @@ -84,7 +126,7 @@ void Differ::MarkDirtyBlocks(const uint8_t* prev_buffer, |
| // If there is a partial column at the end, handle it. |
| // 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
|
| - if (partial_column_width != 0) { |
| + if (partial_column_width > 0) { |
| *diff_info = !PartialBlocksEqual(prev_block, curr_block, bytes_per_row_, |
| partial_column_width, kBlockSize); |
| diff_info += sizeof(bool); |
| @@ -99,19 +141,18 @@ void Differ::MarkDirtyBlocks(const uint8_t* prev_buffer, |
| // If the screen height is not a multiple of the block size, then this |
| // handles the last partial row. This situation is far more common than the |
| // '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.
|
| - if (partial_row_height != 0) { |
| + if (partial_row_height > 0) { |
| const uint8_t* prev_block = prev_block_row_start; |
| const uint8_t* curr_block = curr_block_row_start; |
| bool* diff_info = diff_info_row_start; |
| - for (int x = 0; x < x_full_blocks; x++) { |
| - *diff_info = !PartialBlocksEqual(prev_block, curr_block, |
| - bytes_per_row_, |
| + for (int x = x_start; x < x_end; x++) { |
| + *diff_info = !PartialBlocksEqual(prev_block, curr_block, bytes_per_row_, |
| kBlockSize, partial_row_height); |
| prev_block += block_x_offset; |
| curr_block += block_x_offset; |
| diff_info += sizeof(bool); |
| } |
| - if (partial_column_width != 0) { |
| + if (partial_column_width > 0) { |
| *diff_info = !PartialBlocksEqual(prev_block, curr_block, bytes_per_row_, |
| partial_column_width, |
| partial_row_height); |
| @@ -123,6 +164,7 @@ void Differ::MarkDirtyBlocks(const uint8_t* prev_buffer, |
| bool Differ::PartialBlocksEqual(const uint8_t* prev_buffer, |
| const uint8_t* curr_buffer, |
| int stride, int width, int height) { |
| + RTC_DCHECK(width > 0 && height > 0); |
| int width_bytes = width * bytes_per_pixel_; |
| for (int y = 0; y < height; y++) { |
| if (memcmp(prev_buffer, curr_buffer, width_bytes) != 0) |
| @@ -133,7 +175,7 @@ bool Differ::PartialBlocksEqual(const uint8_t* prev_buffer, |
| return true; |
| } |
| -void Differ::MergeBlocks(DesktopRegion* region) { |
| +void Differ::MergeBlocks(DesktopRegion* region) const { |
| region->Clear(); |
| bool* diff_info_row_start = diff_info_.get(); |