[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 5 | #include "remoting/codec/codec_test.h" |
| 6 | |
avi | 5a080f01 | 2015-12-22 23:15:43 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | #include <stdint.h> |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 9 | #include <stdlib.h> |
sergeyu | 42ad7c0 | 2015-12-24 00:20:51 | [diff] [blame] | 10 | |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 11 | #include <memory> |
sergeyu | 42ad7c0 | 2015-12-24 00:20:51 | [diff] [blame] | 12 | #include <utility> |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 13 | |
[email protected] | 1e1cb3b | 2011-11-10 02:07:41 | [diff] [blame] | 14 | #include "base/bind.h" |
| 15 | #include "base/logging.h" |
avi | 5a080f01 | 2015-12-22 23:15:43 | [diff] [blame] | 16 | #include "base/macros.h" |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 17 | #include "remoting/base/util.h" |
[email protected] | 3860983 | 2012-08-23 01:36:10 | [diff] [blame] | 18 | #include "remoting/codec/video_decoder.h" |
| 19 | #include "remoting/codec/video_encoder.h" |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 20 | #include "remoting/proto/video.pb.h" |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 21 | #include "testing/gtest/include/gtest/gtest.h" |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 22 | #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| 23 | |
[email protected] | c5a0f601 | 2014-07-01 06:44:34 | [diff] [blame] | 24 | using webrtc::BasicDesktopFrame; |
| 25 | using webrtc::DesktopFrame; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 26 | using webrtc::DesktopRect; |
[email protected] | f301d736 | 2013-06-05 00:02:02 | [diff] [blame] | 27 | using webrtc::DesktopRegion; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 28 | using webrtc::DesktopSize; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 29 | |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 30 | namespace { |
| 31 | |
| 32 | const int kBytesPerPixel = 4; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 33 | |
| 34 | // Some sample rects for testing. |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 35 | std::vector<DesktopRegion> MakeTestRegionLists(DesktopSize size) { |
| 36 | std::vector<DesktopRegion> region_lists; |
| 37 | DesktopRegion region; |
| 38 | region.AddRect(DesktopRect::MakeXYWH(0, 0, size.width(), size.height())); |
| 39 | region_lists.push_back(region); |
| 40 | region.Clear(); |
| 41 | region.AddRect( |
| 42 | DesktopRect::MakeXYWH(0, 0, size.width() / 2, size.height() / 2)); |
| 43 | region_lists.push_back(region); |
| 44 | region.Clear(); |
| 45 | region.AddRect(DesktopRect::MakeXYWH(size.width() / 2, size.height() / 2, |
| 46 | size.width() / 2, size.height() / 2)); |
| 47 | region_lists.push_back(region); |
| 48 | region.Clear(); |
| 49 | region.AddRect(DesktopRect::MakeXYWH(16, 16, 16, 16)); |
| 50 | region.AddRect(DesktopRect::MakeXYWH(32, 32, 32, 32)); |
| 51 | region.IntersectWith(DesktopRect::MakeSize(size)); |
| 52 | region_lists.push_back(region); |
| 53 | return region_lists; |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 54 | } |
| 55 | |
| 56 | } // namespace |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 57 | |
| 58 | namespace remoting { |
| 59 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 60 | class VideoDecoderTester { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 61 | public: |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 62 | VideoDecoderTester(VideoDecoder* decoder, const DesktopSize& screen_size) |
| 63 | : strict_(false), |
[email protected] | a3c1d45 | 2013-08-21 18:51:40 | [diff] [blame] | 64 | decoder_(decoder), |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 65 | frame_(new BasicDesktopFrame(screen_size)), |
| 66 | expected_frame_(nullptr) {} |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 67 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 68 | void Reset() { |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 69 | frame_.reset(new BasicDesktopFrame(frame_->size())); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 70 | expected_region_.Clear(); |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 71 | } |
[email protected] | cee5dba | 2010-12-07 03:19:48 | [diff] [blame] | 72 | |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 73 | void ResetRenderedData() { |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 74 | memset(frame_->data(), 0, |
| 75 | frame_->size().width() * frame_->size().height() * kBytesPerPixel); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 76 | } |
| 77 | |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 78 | void ReceivedPacket(std::unique_ptr<VideoPacket> packet) { |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 79 | ASSERT_TRUE(decoder_->DecodePacket(*packet, frame_.get())); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 80 | } |
| 81 | |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 82 | void set_strict(bool strict) { |
| 83 | strict_ = strict; |
| 84 | } |
| 85 | |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 86 | void set_expected_frame(DesktopFrame* frame) { |
| 87 | expected_frame_ = frame; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 88 | } |
| 89 | |
[email protected] | c5a0f601 | 2014-07-01 06:44:34 | [diff] [blame] | 90 | void AddRegion(const DesktopRegion& region) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 91 | expected_region_.AddRegion(region); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 92 | } |
| 93 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 94 | void VerifyResults() { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 95 | if (!strict_) |
| 96 | return; |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 97 | |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 98 | ASSERT_TRUE(expected_frame_); |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 99 | |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 100 | // Test the content of the update region. |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 101 | EXPECT_TRUE(expected_region_.Equals(frame_->updated_region())); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 102 | |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 103 | for (DesktopRegion::Iterator i(frame_->updated_region()); !i.IsAtEnd(); |
[email protected] | e59d659 | 2013-09-25 22:16:21 | [diff] [blame] | 104 | i.Advance()) { |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 105 | const uint8_t* original = |
| 106 | expected_frame_->GetFrameDataAtPos(i.rect().top_left()); |
| 107 | const uint8_t* decoded = |
| 108 | frame_->GetFrameDataAtPos(i.rect().top_left()); |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 109 | const int row_size = kBytesPerPixel * i.rect().width(); |
| 110 | for (int y = 0; y < i.rect().height(); ++y) { |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 111 | EXPECT_EQ(0, memcmp(original, decoded, row_size)) |
| 112 | << "Row " << y << " is different"; |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 113 | original += expected_frame_->stride(); |
| 114 | decoded += frame_->stride(); |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 115 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 116 | } |
| 117 | } |
| 118 | |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 119 | // The error at each pixel is the root mean square of the errors in |
| 120 | // the R, G, and B components, each normalized to [0, 1]. This routine |
| 121 | // checks that the maximum and mean pixel errors do not exceed given limits. |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 122 | void VerifyResultsApprox(double max_error_limit, double mean_error_limit) { |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 123 | double max_error = 0.0; |
| 124 | double sum_error = 0.0; |
| 125 | int error_num = 0; |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 126 | for (DesktopRegion::Iterator i(frame_->updated_region()); !i.IsAtEnd(); |
[email protected] | e59d659 | 2013-09-25 22:16:21 | [diff] [blame] | 127 | i.Advance()) { |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 128 | const uint8_t* expected = |
| 129 | expected_frame_->GetFrameDataAtPos(i.rect().top_left()); |
| 130 | const uint8_t* actual = |
| 131 | frame_->GetFrameDataAtPos(i.rect().top_left()); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 132 | for (int y = 0; y < i.rect().height(); ++y) { |
| 133 | for (int x = 0; x < i.rect().width(); ++x) { |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 134 | double error = CalculateError(expected + x * kBytesPerPixel, |
| 135 | actual + x * kBytesPerPixel); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 136 | max_error = std::max(max_error, error); |
| 137 | sum_error += error; |
| 138 | ++error_num; |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 139 | } |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 140 | expected += expected_frame_->stride(); |
| 141 | actual += frame_->stride(); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 142 | } |
| 143 | } |
| 144 | EXPECT_LE(max_error, max_error_limit); |
| 145 | double mean_error = sum_error / error_num; |
| 146 | EXPECT_LE(mean_error, mean_error_limit); |
[email protected] | 5cbe3cf | 2013-11-25 17:05:04 | [diff] [blame] | 147 | VLOG(0) << "Max error: " << max_error; |
| 148 | VLOG(0) << "Mean error: " << mean_error; |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 149 | } |
| 150 | |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 151 | double CalculateError(const uint8_t* original, const uint8_t* decoded) { |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 152 | double error_sum_squares = 0.0; |
| 153 | for (int i = 0; i < 3; i++) { |
| 154 | double error = static_cast<double>(*original++) - |
| 155 | static_cast<double>(*decoded++); |
| 156 | error /= 255.0; |
| 157 | error_sum_squares += error * error; |
| 158 | } |
| 159 | original++; |
| 160 | decoded++; |
| 161 | return sqrt(error_sum_squares / 3.0); |
| 162 | } |
| 163 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 164 | private: |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 165 | bool strict_; |
[email protected] | c5a0f601 | 2014-07-01 06:44:34 | [diff] [blame] | 166 | DesktopRegion expected_region_; |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 167 | VideoDecoder* decoder_; |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 168 | std::unique_ptr<DesktopFrame> frame_; |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 169 | DesktopFrame* expected_frame_; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 170 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 171 | DISALLOW_COPY_AND_ASSIGN(VideoDecoderTester); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 172 | }; |
| 173 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 174 | // The VideoEncoderTester provides a hook for retrieving the data, and passing |
| 175 | // the message to other subprograms for validaton. |
| 176 | class VideoEncoderTester { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 177 | public: |
wez | 070889b | 2015-07-17 03:19:15 | [diff] [blame] | 178 | VideoEncoderTester() : decoder_tester_(nullptr), data_available_(0) {} |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 179 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 180 | ~VideoEncoderTester() { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 181 | EXPECT_GT(data_available_, 0); |
| 182 | } |
| 183 | |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 184 | void DataAvailable(std::unique_ptr<VideoPacket> packet) { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 185 | ++data_available_; |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 186 | // Send the message to the VideoDecoderTester. |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 187 | if (decoder_tester_) { |
sergeyu | 42ad7c0 | 2015-12-24 00:20:51 | [diff] [blame] | 188 | decoder_tester_->ReceivedPacket(std::move(packet)); |
[email protected] | cee5dba | 2010-12-07 03:19:48 | [diff] [blame] | 189 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 190 | } |
| 191 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 192 | void set_decoder_tester(VideoDecoderTester* decoder_tester) { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 193 | decoder_tester_ = decoder_tester; |
| 194 | } |
| 195 | |
| 196 | private: |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 197 | VideoDecoderTester* decoder_tester_; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 198 | int data_available_; |
| 199 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 200 | DISALLOW_COPY_AND_ASSIGN(VideoEncoderTester); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 201 | }; |
| 202 | |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 203 | std::unique_ptr<DesktopFrame> PrepareFrame(const DesktopSize& size) { |
| 204 | std::unique_ptr<DesktopFrame> frame(new BasicDesktopFrame(size)); |
[email protected] | 04499fb | 2012-08-25 00:33:50 | [diff] [blame] | 205 | |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 206 | srand(0); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 207 | int memory_size = size.width() * size.height() * kBytesPerPixel; |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 208 | for (int i = 0; i < memory_size; ++i) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 209 | frame->data()[i] = rand() % 256; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 210 | } |
| 211 | |
sergeyu | 42ad7c0 | 2015-12-24 00:20:51 | [diff] [blame] | 212 | return frame; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 213 | } |
| 214 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 215 | static void TestEncodingRects(VideoEncoder* encoder, |
| 216 | VideoEncoderTester* tester, |
wez | 43ac266 | 2015-06-10 18:22:29 | [diff] [blame] | 217 | DesktopFrame* frame, |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 218 | const DesktopRegion& region) { |
| 219 | *frame->mutable_updated_region() = region; |
sergeyu | 2becb601 | 2016-09-13 18:41:32 | [diff] [blame] | 220 | tester->DataAvailable(encoder->Encode(*frame)); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 221 | } |
| 222 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 223 | void TestVideoEncoder(VideoEncoder* encoder, bool strict) { |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 224 | const int kSizes[] = {80, 79, 77, 54}; |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 225 | |
[email protected] | 8b6d3d0 | 2013-09-13 22:43:41 | [diff] [blame] | 226 | VideoEncoderTester tester; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 227 | |
[email protected] | 8c6d71d | 2012-10-23 21:20:04 | [diff] [blame] | 228 | for (size_t xi = 0; xi < arraysize(kSizes); ++xi) { |
| 229 | for (size_t yi = 0; yi < arraysize(kSizes); ++yi) { |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 230 | DesktopSize size(kSizes[xi], kSizes[yi]); |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 231 | std::unique_ptr<DesktopFrame> frame = PrepareFrame(size); |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 232 | for (const DesktopRegion& region : MakeTestRegionLists(size)) { |
| 233 | TestEncodingRects(encoder, &tester, frame.get(), region); |
[email protected] | 8c6d71d | 2012-10-23 21:20:04 | [diff] [blame] | 234 | } |
wez | 43ac266 | 2015-06-10 18:22:29 | [diff] [blame] | 235 | |
| 236 | // Pass some empty frames through the encoder. |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 237 | for (int i = 0; i < 5; ++i) { |
| 238 | TestEncodingRects(encoder, &tester, frame.get(), DesktopRegion()); |
wez | 43ac266 | 2015-06-10 18:22:29 | [diff] [blame] | 239 | } |
[email protected] | 8c6d71d | 2012-10-23 21:20:04 | [diff] [blame] | 240 | } |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 241 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 242 | } |
| 243 | |
wez | 9242f6c | 2015-07-10 21:43:33 | [diff] [blame] | 244 | void TestVideoEncoderEmptyFrames(VideoEncoder* encoder, |
| 245 | int max_topoff_frames) { |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 246 | const DesktopSize kSize(100, 100); |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 247 | std::unique_ptr<DesktopFrame> frame(PrepareFrame(kSize)); |
wez | 43ac266 | 2015-06-10 18:22:29 | [diff] [blame] | 248 | |
| 249 | frame->mutable_updated_region()->SetRect( |
| 250 | webrtc::DesktopRect::MakeSize(kSize)); |
sergeyu | 2becb601 | 2016-09-13 18:41:32 | [diff] [blame] | 251 | EXPECT_TRUE(encoder->Encode(*frame)); |
wez | 43ac266 | 2015-06-10 18:22:29 | [diff] [blame] | 252 | |
wez | 9242f6c | 2015-07-10 21:43:33 | [diff] [blame] | 253 | int topoff_frames = 0; |
wez | 43ac266 | 2015-06-10 18:22:29 | [diff] [blame] | 254 | frame->mutable_updated_region()->Clear(); |
wez | 9242f6c | 2015-07-10 21:43:33 | [diff] [blame] | 255 | for (int i = 0; i < max_topoff_frames + 1; ++i) { |
sergeyu | 2becb601 | 2016-09-13 18:41:32 | [diff] [blame] | 256 | if (!encoder->Encode(*frame)) |
wez | 9242f6c | 2015-07-10 21:43:33 | [diff] [blame] | 257 | break; |
| 258 | topoff_frames++; |
wez | 43ac266 | 2015-06-10 18:22:29 | [diff] [blame] | 259 | } |
| 260 | |
wez | 9242f6c | 2015-07-10 21:43:33 | [diff] [blame] | 261 | // If top-off is enabled then our random frame contents should always |
| 262 | // trigger it, so expect at least one top-off frame - strictly, though, |
| 263 | // an encoder may not always need to top-off. |
| 264 | EXPECT_GE(topoff_frames, max_topoff_frames ? 1 : 0); |
| 265 | EXPECT_LE(topoff_frames, max_topoff_frames); |
wez | 43ac266 | 2015-06-10 18:22:29 | [diff] [blame] | 266 | } |
| 267 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 268 | static void TestEncodeDecodeRects(VideoEncoder* encoder, |
| 269 | VideoEncoderTester* encoder_tester, |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 270 | VideoDecoderTester* decoder_tester, |
[email protected] | c5a0f601 | 2014-07-01 06:44:34 | [diff] [blame] | 271 | DesktopFrame* frame, |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 272 | const DesktopRegion& region) { |
| 273 | *frame->mutable_updated_region() = region; |
| 274 | decoder_tester->AddRegion(region); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 275 | |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 276 | // Generate random data for the updated region. |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 277 | srand(0); |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 278 | for (DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) { |
| 279 | const int row_size = DesktopFrame::kBytesPerPixel * i.rect().width(); |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 280 | uint8_t* memory = frame->data() + frame->stride() * i.rect().top() + |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 281 | DesktopFrame::kBytesPerPixel * i.rect().left(); |
| 282 | for (int y = 0; y < i.rect().height(); ++y) { |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 283 | for (int x = 0; x < row_size; ++x) |
| 284 | memory[x] = rand() % 256; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 285 | memory += frame->stride(); |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 286 | } |
| 287 | } |
| 288 | |
sergeyu | 2becb601 | 2016-09-13 18:41:32 | [diff] [blame] | 289 | encoder_tester->DataAvailable(encoder->Encode(*frame)); |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 290 | decoder_tester->VerifyResults(); |
| 291 | decoder_tester->Reset(); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 292 | } |
| 293 | |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 294 | void TestVideoEncoderDecoder(VideoEncoder* encoder, |
| 295 | VideoDecoder* decoder, |
| 296 | bool strict) { |
| 297 | DesktopSize kSize = DesktopSize(160, 120); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 298 | |
[email protected] | 8b6d3d0 | 2013-09-13 22:43:41 | [diff] [blame] | 299 | VideoEncoderTester encoder_tester; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 300 | |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 301 | std::unique_ptr<DesktopFrame> frame = PrepareFrame(kSize); |
[email protected] | dc454a7c | 2011-08-12 22:01:13 | [diff] [blame] | 302 | |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 303 | VideoDecoderTester decoder_tester(decoder, kSize); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 304 | decoder_tester.set_strict(strict); |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 305 | decoder_tester.set_expected_frame(frame.get()); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 306 | encoder_tester.set_decoder_tester(&decoder_tester); |
| 307 | |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 308 | for (const DesktopRegion& region : MakeTestRegionLists(kSize)) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 309 | TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, |
sergeyu | fc59cb4 | 2015-07-30 22:19:25 | [diff] [blame] | 310 | frame.get(), region); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 311 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 312 | } |
| 313 | |
[email protected] | c5a0f601 | 2014-07-01 06:44:34 | [diff] [blame] | 314 | static void FillWithGradient(DesktopFrame* frame) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 315 | for (int j = 0; j < frame->size().height(); ++j) { |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 316 | uint8_t* p = frame->data() + j * frame->stride(); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 317 | for (int i = 0; i < frame->size().width(); ++i) { |
| 318 | *p++ = (255.0 * i) / frame->size().width(); |
| 319 | *p++ = (164.0 * j) / frame->size().height(); |
| 320 | *p++ = (82.0 * (i + j)) / |
| 321 | (frame->size().width() + frame->size().height()); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 322 | *p++ = 0; |
| 323 | } |
| 324 | } |
| 325 | } |
| 326 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 327 | void TestVideoEncoderDecoderGradient(VideoEncoder* encoder, |
| 328 | VideoDecoder* decoder, |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 329 | const DesktopSize& screen_size, |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 330 | double max_error_limit, |
| 331 | double mean_error_limit) { |
dcheng | 0765c49 | 2016-04-06 22:41:53 | [diff] [blame] | 332 | std::unique_ptr<BasicDesktopFrame> frame(new BasicDesktopFrame(screen_size)); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 333 | FillWithGradient(frame.get()); |
| 334 | frame->mutable_updated_region()->SetRect(DesktopRect::MakeSize(screen_size)); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 335 | |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 336 | VideoDecoderTester decoder_tester(decoder, screen_size); |
| 337 | decoder_tester.set_expected_frame(frame.get()); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 338 | decoder_tester.AddRegion(frame->updated_region()); |
sergeyu | 2becb601 | 2016-09-13 18:41:32 | [diff] [blame] | 339 | decoder_tester.ReceivedPacket(encoder->Encode(*frame)); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 340 | |
sergeyu | ef92de20 | 2015-08-20 22:47:37 | [diff] [blame] | 341 | decoder_tester.VerifyResultsApprox(max_error_limit, mean_error_limit); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 342 | } |
| 343 | |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 344 | } // namespace remoting |