tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

desktop_capturer_differ_wrapper_unittest.cc (13763B)


      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 "modules/desktop_capture/desktop_capturer_differ_wrapper.h"
     12 
     13 #include <initializer_list>
     14 #include <memory>
     15 #include <utility>
     16 #include <vector>
     17 
     18 #include "api/units/time_delta.h"
     19 #include "api/units/timestamp.h"
     20 #include "modules/desktop_capture/desktop_capturer.h"
     21 #include "modules/desktop_capture/desktop_frame.h"
     22 #include "modules/desktop_capture/desktop_frame_generator.h"
     23 #include "modules/desktop_capture/desktop_geometry.h"
     24 #include "modules/desktop_capture/desktop_region.h"
     25 #include "modules/desktop_capture/differ_block.h"
     26 #include "modules/desktop_capture/fake_desktop_capturer.h"
     27 #include "modules/desktop_capture/mock_desktop_capturer_callback.h"
     28 #include "rtc_base/random.h"
     29 #include "system_wrappers/include/clock.h"
     30 #include "test/gmock.h"
     31 #include "test/gtest.h"
     32 
     33 namespace webrtc {
     34 
     35 namespace {
     36 
     37 // Compares and asserts `frame`.updated_region() equals to `rects`. This
     38 // function does not care about the order of the `rects` and it does not expect
     39 // DesktopRegion to return an exact area for each rectangle in `rects`.
     40 template <template <typename, typename...> class T = std::initializer_list,
     41          typename... Rect>
     42 void AssertUpdatedRegionIs(const DesktopFrame& frame,
     43                           const T<DesktopRect, Rect...>& rects) {
     44  DesktopRegion region;
     45  for (const auto& rect : rects) {
     46    region.AddRect(rect);
     47  }
     48  ASSERT_TRUE(frame.updated_region().Equals(region));
     49 }
     50 
     51 // Compares and asserts `frame`.updated_region() covers all rectangles in
     52 // `rects`, but does not cover areas other than a kBlockSize expansion. This
     53 // function does not care about the order of the `rects`, and it does not expect
     54 // DesktopRegion to return an exact area of each rectangle in `rects`.
     55 template <template <typename, typename...> class T = std::initializer_list,
     56          typename... Rect>
     57 void AssertUpdatedRegionCovers(const DesktopFrame& frame,
     58                               const T<DesktopRect, Rect...>& rects) {
     59  DesktopRegion region;
     60  for (const auto& rect : rects) {
     61    region.AddRect(rect);
     62  }
     63 
     64  // Intersect of `rects` and `frame`.updated_region() should be `rects`. i.e.
     65  // `frame`.updated_region() should be a superset of `rects`.
     66  DesktopRegion intersect(region);
     67  intersect.IntersectWith(frame.updated_region());
     68  ASSERT_TRUE(region.Equals(intersect));
     69 
     70  // Difference between `rects` and `frame`.updated_region() should not cover
     71  // areas which have larger than twice of kBlockSize width and height.
     72  //
     73  // Explanation of the 'twice' of kBlockSize (indeed kBlockSize * 2 - 2) is
     74  // following,
     75  // (Each block in the following grid is a 8 x 8 pixels area. X means the real
     76  // updated area, m means the updated area marked by
     77  // DesktopCapturerDifferWrapper.)
     78  // +---+---+---+---+---+---+---+---+
     79  // | X | m | m | m | m | m | m | m |
     80  // +---+---+---+---+---+---+---+---+
     81  // | m | m | m | m | m | m | m | m |
     82  // +---+---+---+---+---+---+---+---+
     83  // | m | m | m | m | m | m | m | m |
     84  // +---+---+---+---+---+---+---+---+
     85  // | m | m | m | m | m | m | m | X |
     86  // +---+---+---+---+---+---+---+---+
     87  // The top left [0, 0] - [8, 8] and right bottom [56, 24] - [64, 32] blocks of
     88  // this area are updated. But since DesktopCapturerDifferWrapper compares
     89  // 32 x 32 blocks by default, this entire area is marked as updated. So the
     90  // [8, 8] - [56, 32] is expected to be covered in the difference.
     91  //
     92  // But if [0, 0] - [8, 8] and [64, 24] - [72, 32] blocks are updated,
     93  // +---+---+---+---+---+---+---+---+---+---+---+---+
     94  // | X | m | m | m |   |   |   |   | m | m | m | m |
     95  // +---+---+---+---+---+---+---+---+---+---+---+---+
     96  // | m | m | m | m |   |   |   |   | m | m | m | m |
     97  // +---+---+---+---+---+---+---+---+---+---+---+---+
     98  // | m | m | m | m |   |   |   |   | m | m | m | m |
     99  // +---+---+---+---+---+---+---+---+---+---+---+---+
    100  // | m | m | m | m |   |   |   |   | X | m | m | m |
    101  // +---+---+---+---+---+---+---+---+---+---+---+---+
    102  // the [8, 8] - [64, 32] is not expected to be covered in the difference. As
    103  // DesktopCapturerDifferWrapper should only mark [0, 0] - [32, 32] and
    104  // [64, 0] - [96, 32] as updated.
    105  DesktopRegion differ(frame.updated_region());
    106  differ.Subtract(region);
    107  for (DesktopRegion::Iterator it(differ); !it.IsAtEnd(); it.Advance()) {
    108    ASSERT_TRUE(it.rect().width() <= kBlockSize * 2 - 2 ||
    109                it.rect().height() <= kBlockSize * 2 - 2);
    110  }
    111 }
    112 
    113 // Executes a DesktopCapturerDifferWrapper::Capture() and compares its output
    114 // DesktopFrame::updated_region() with `updated_region` if `check_result` is
    115 // true. If `exactly_match` is true, AssertUpdatedRegionIs() will be used,
    116 // otherwise AssertUpdatedRegionCovers() will be used.
    117 template <template <typename, typename...> class T = std::initializer_list,
    118          typename... Rect>
    119 void ExecuteDifferWrapperCase(BlackWhiteDesktopFramePainter* frame_painter,
    120                              DesktopCapturerDifferWrapper* capturer,
    121                              MockDesktopCapturerCallback* callback,
    122                              const T<DesktopRect, Rect...>& updated_region,
    123                              bool check_result,
    124                              bool exactly_match) {
    125  EXPECT_CALL(*callback, OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS,
    126                                            ::testing::_))
    127      .Times(1)
    128      .WillOnce(
    129          ::testing::Invoke([&updated_region, check_result, exactly_match](
    130                                DesktopCapturer::Result result,
    131                                std::unique_ptr<DesktopFrame>* frame) {
    132            ASSERT_EQ(result, DesktopCapturer::Result::SUCCESS);
    133            if (check_result) {
    134              if (exactly_match) {
    135                AssertUpdatedRegionIs(**frame, updated_region);
    136              } else {
    137                AssertUpdatedRegionCovers(**frame, updated_region);
    138              }
    139            }
    140          }));
    141  for (const auto& rect : updated_region) {
    142    frame_painter->updated_region()->AddRect(rect);
    143  }
    144  capturer->CaptureFrame();
    145 }
    146 
    147 // Executes a DesktopCapturerDifferWrapper::Capture(), if updated_region() is
    148 // not set, this function will reset DesktopCapturerDifferWrapper internal
    149 // DesktopFrame into black.
    150 void ExecuteCapturer(DesktopCapturerDifferWrapper* capturer,
    151                     MockDesktopCapturerCallback* callback) {
    152  EXPECT_CALL(*callback, OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS,
    153                                            ::testing::_))
    154      .Times(1);
    155  capturer->CaptureFrame();
    156 }
    157 
    158 void ExecuteDifferWrapperTest(Clock* clock,
    159                              bool with_hints,
    160                              bool enlarge_updated_region,
    161                              bool random_updated_region,
    162                              bool check_result) {
    163  const bool updated_region_should_exactly_match =
    164      with_hints && !enlarge_updated_region && !random_updated_region;
    165  BlackWhiteDesktopFramePainter frame_painter;
    166  PainterDesktopFrameGenerator frame_generator;
    167  frame_generator.set_desktop_frame_painter(&frame_painter);
    168  std::unique_ptr<FakeDesktopCapturer> fake(new FakeDesktopCapturer());
    169  fake->set_frame_generator(&frame_generator);
    170  DesktopCapturerDifferWrapper capturer(std::move(fake));
    171  MockDesktopCapturerCallback callback;
    172  frame_generator.set_provide_updated_region_hints(with_hints);
    173  frame_generator.set_enlarge_updated_region(enlarge_updated_region);
    174  frame_generator.set_add_random_updated_region(random_updated_region);
    175 
    176  capturer.Start(&callback);
    177 
    178  EXPECT_CALL(callback, OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS,
    179                                           ::testing::_))
    180      .Times(1)
    181      .WillOnce(::testing::Invoke([](DesktopCapturer::Result result,
    182                                     std::unique_ptr<DesktopFrame>* frame) {
    183        ASSERT_EQ(result, DesktopCapturer::Result::SUCCESS);
    184        AssertUpdatedRegionIs(**frame,
    185                              {DesktopRect::MakeSize((*frame)->size())});
    186      }));
    187  capturer.CaptureFrame();
    188 
    189  ExecuteDifferWrapperCase(&frame_painter, &capturer, &callback,
    190                           {DesktopRect::MakeLTRB(100, 100, 200, 200),
    191                            DesktopRect::MakeLTRB(300, 300, 400, 400)},
    192                           check_result, updated_region_should_exactly_match);
    193  ExecuteCapturer(&capturer, &callback);
    194 
    195  ExecuteDifferWrapperCase(
    196      &frame_painter, &capturer, &callback,
    197      {DesktopRect::MakeLTRB(0, 0, 40, 40),
    198       DesktopRect::MakeLTRB(0, frame_generator.size()->height() - 40, 40,
    199                             frame_generator.size()->height()),
    200       DesktopRect::MakeLTRB(frame_generator.size()->width() - 40, 0,
    201                             frame_generator.size()->width(), 40),
    202       DesktopRect::MakeLTRB(frame_generator.size()->width() - 40,
    203                             frame_generator.size()->height() - 40,
    204                             frame_generator.size()->width(),
    205                             frame_generator.size()->height())},
    206      check_result, updated_region_should_exactly_match);
    207 
    208  Random random(clock->TimeInMilliseconds());
    209  // Fuzzing tests.
    210  for (int i = 0; i < 1000; i++) {
    211    if (enlarge_updated_region) {
    212      frame_generator.set_enlarge_range(random.Rand(1, 50));
    213    }
    214    frame_generator.size()->set(random.Rand(500, 2000), random.Rand(500, 2000));
    215    ExecuteCapturer(&capturer, &callback);
    216    std::vector<DesktopRect> updated_region;
    217    for (int j = random.Rand(50); j >= 0; j--) {
    218      // At least a 1 x 1 updated region.
    219      const int left = random.Rand(0, frame_generator.size()->width() - 2);
    220      const int top = random.Rand(0, frame_generator.size()->height() - 2);
    221      const int right = random.Rand(left + 1, frame_generator.size()->width());
    222      const int bottom = random.Rand(top + 1, frame_generator.size()->height());
    223      updated_region.push_back(DesktopRect::MakeLTRB(left, top, right, bottom));
    224    }
    225    ExecuteDifferWrapperCase(&frame_painter, &capturer, &callback,
    226                             updated_region, check_result,
    227                             updated_region_should_exactly_match);
    228  }
    229 }
    230 
    231 }  // namespace
    232 
    233 TEST(DesktopCapturerDifferWrapperTest, CaptureWithoutHints) {
    234  Clock* clock = Clock::GetRealTimeClock();
    235  ExecuteDifferWrapperTest(clock, false, false, false, true);
    236 }
    237 
    238 TEST(DesktopCapturerDifferWrapperTest, CaptureWithHints) {
    239  Clock* clock = Clock::GetRealTimeClock();
    240  ExecuteDifferWrapperTest(clock, true, false, false, true);
    241 }
    242 
    243 TEST(DesktopCapturerDifferWrapperTest, CaptureWithEnlargedHints) {
    244  Clock* clock = Clock::GetRealTimeClock();
    245  ExecuteDifferWrapperTest(clock, true, true, false, true);
    246 }
    247 
    248 TEST(DesktopCapturerDifferWrapperTest, CaptureWithRandomHints) {
    249  Clock* clock = Clock::GetRealTimeClock();
    250  ExecuteDifferWrapperTest(clock, true, false, true, true);
    251 }
    252 
    253 TEST(DesktopCapturerDifferWrapperTest, CaptureWithEnlargedAndRandomHints) {
    254  Clock* clock = Clock::GetRealTimeClock();
    255  ExecuteDifferWrapperTest(clock, true, true, true, true);
    256 }
    257 
    258 // When hints are provided, DesktopCapturerDifferWrapper has a slightly better
    259 // performance in current configuration, but not so significant. Following is
    260 // one run result.
    261 // [ RUN      ] DISABLED_CaptureWithoutHintsPerf
    262 // [       OK ] DISABLED_CaptureWithoutHintsPerf (7118 ms)
    263 // [ RUN      ] DISABLED_CaptureWithHintsPerf
    264 // [       OK ] DISABLED_CaptureWithHintsPerf (5580 ms)
    265 // [ RUN      ] DISABLED_CaptureWithEnlargedHintsPerf
    266 // [       OK ] DISABLED_CaptureWithEnlargedHintsPerf (5974 ms)
    267 // [ RUN      ] DISABLED_CaptureWithRandomHintsPerf
    268 // [       OK ] DISABLED_CaptureWithRandomHintsPerf (6184 ms)
    269 // [ RUN      ] DISABLED_CaptureWithEnlargedAndRandomHintsPerf
    270 // [       OK ] DISABLED_CaptureWithEnlargedAndRandomHintsPerf (6347 ms)
    271 TEST(DesktopCapturerDifferWrapperTest, DISABLED_CaptureWithoutHintsPerf) {
    272  Clock* clock = Clock::GetRealTimeClock();
    273  const Timestamp started = clock->CurrentTime();
    274  ExecuteDifferWrapperTest(clock, false, false, false, false);
    275  ASSERT_LE(clock->CurrentTime() - started, TimeDelta::Millis(15000));
    276 }
    277 
    278 TEST(DesktopCapturerDifferWrapperTest, DISABLED_CaptureWithHintsPerf) {
    279  Clock* clock = Clock::GetRealTimeClock();
    280  const Timestamp started = clock->CurrentTime();
    281  ExecuteDifferWrapperTest(clock, true, false, false, false);
    282  ASSERT_LE(clock->CurrentTime() - started, TimeDelta::Millis(15000));
    283 }
    284 
    285 TEST(DesktopCapturerDifferWrapperTest, DISABLED_CaptureWithEnlargedHintsPerf) {
    286  Clock* clock = Clock::GetRealTimeClock();
    287  const Timestamp started = clock->CurrentTime();
    288  ExecuteDifferWrapperTest(clock, true, true, false, false);
    289  ASSERT_LE(clock->CurrentTime() - started, TimeDelta::Millis(15000));
    290 }
    291 
    292 TEST(DesktopCapturerDifferWrapperTest, DISABLED_CaptureWithRandomHintsPerf) {
    293  Clock* clock = Clock::GetRealTimeClock();
    294  const Timestamp started = clock->CurrentTime();
    295  ExecuteDifferWrapperTest(clock, true, false, true, false);
    296  ASSERT_LE(clock->CurrentTime() - started, TimeDelta::Millis(15000));
    297 }
    298 
    299 TEST(DesktopCapturerDifferWrapperTest,
    300     DISABLED_CaptureWithEnlargedAndRandomHintsPerf) {
    301  Clock* clock = Clock::GetRealTimeClock();
    302  const Timestamp started = clock->CurrentTime();
    303  ExecuteDifferWrapperTest(clock, true, true, true, false);
    304  ASSERT_LE(clock->CurrentTime() - started, TimeDelta::Millis(15000));
    305 }
    306 
    307 }  // namespace webrtc