[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 | |
[email protected] | 542bdfe | 2010-11-30 03:55:47 | [diff] [blame] | 5 | #include <deque> |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 6 | #include <stdlib.h> |
| 7 | |
[email protected] | 1e1cb3b | 2011-11-10 02:07:41 | [diff] [blame] | 8 | #include "base/bind.h" |
| 9 | #include "base/logging.h" |
[email protected] | dc454a7c | 2011-08-12 22:01:13 | [diff] [blame] | 10 | #include "base/memory/scoped_ptr.h" |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 11 | #include "media/base/video_frame.h" |
[email protected] | 3860983 | 2012-08-23 01:36:10 | [diff] [blame] | 12 | #include "remoting/codec/codec_test.h" |
| 13 | #include "remoting/codec/video_decoder.h" |
| 14 | #include "remoting/codec/video_encoder.h" |
[email protected] | c3af26f33 | 2010-10-06 22:46:00 | [diff] [blame] | 15 | #include "remoting/base/util.h" |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 16 | #include "testing/gtest/include/gtest/gtest.h" |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 17 | #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| 18 | |
| 19 | using webrtc::DesktopRect; |
[email protected] | f301d736 | 2013-06-05 00:02:02 | [diff] [blame] | 20 | using webrtc::DesktopRegion; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 21 | using webrtc::DesktopSize; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 22 | |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 23 | namespace { |
| 24 | |
| 25 | const int kBytesPerPixel = 4; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 26 | |
| 27 | // Some sample rects for testing. |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 28 | std::vector<std::vector<DesktopRect> > MakeTestRectLists(DesktopSize size) { |
| 29 | std::vector<std::vector<DesktopRect> > rect_lists; |
| 30 | std::vector<DesktopRect> rects; |
| 31 | rects.push_back(DesktopRect::MakeXYWH(0, 0, size.width(), size.height())); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 32 | rect_lists.push_back(rects); |
| 33 | rects.clear(); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 34 | rects.push_back(DesktopRect::MakeXYWH( |
| 35 | 0, 0, size.width() / 2, size.height() / 2)); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 36 | rect_lists.push_back(rects); |
| 37 | rects.clear(); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 38 | rects.push_back(DesktopRect::MakeXYWH( |
| 39 | size.width() / 2, size.height() / 2, |
| 40 | size.width() / 2, size.height() / 2)); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 41 | rect_lists.push_back(rects); |
| 42 | rects.clear(); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 43 | rects.push_back(DesktopRect::MakeXYWH(16, 16, 16, 16)); |
| 44 | rects.push_back(DesktopRect::MakeXYWH(128, 64, 32, 32)); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 45 | rect_lists.push_back(rects); |
| 46 | return rect_lists; |
| 47 | } |
| 48 | |
| 49 | } // namespace |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 50 | |
| 51 | namespace remoting { |
| 52 | |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 53 | // A class to test the message output of the encoder. |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 54 | class VideoEncoderMessageTester { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 55 | public: |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 56 | VideoEncoderMessageTester() |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 57 | : begin_rect_(0), |
| 58 | rect_data_(0), |
| 59 | end_rect_(0), |
| 60 | state_(kWaitingForBeginRect), |
| 61 | strict_(false) { |
| 62 | } |
| 63 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 64 | ~VideoEncoderMessageTester() { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 65 | EXPECT_EQ(begin_rect_, end_rect_); |
[email protected] | df10bf1 | 2010-09-28 22:19:48 | [diff] [blame] | 66 | EXPECT_GT(begin_rect_, 0); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 67 | EXPECT_EQ(kWaitingForBeginRect, state_); |
[email protected] | df10bf1 | 2010-09-28 22:19:48 | [diff] [blame] | 68 | if (strict_) { |
[email protected] | f301d736 | 2013-06-05 00:02:02 | [diff] [blame] | 69 | EXPECT_TRUE(region_.Equals(received_region_)); |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 70 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 71 | } |
| 72 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 73 | // Test that we received the correct packet. |
| 74 | void ReceivedPacket(VideoPacket* packet) { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 75 | if (state_ == kWaitingForBeginRect) { |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 76 | EXPECT_TRUE((packet->flags() & VideoPacket::FIRST_PACKET) != 0); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 77 | state_ = kWaitingForRectData; |
| 78 | ++begin_rect_; |
| 79 | |
| 80 | if (strict_) { |
[email protected] | f301d736 | 2013-06-05 00:02:02 | [diff] [blame] | 81 | received_region_.AddRect(webrtc::DesktopRect::MakeXYWH( |
| 82 | packet->format().x(), packet->format().y(), |
| 83 | packet->format().width(), packet->format().height())); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 84 | } |
| 85 | } else { |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 86 | EXPECT_FALSE((packet->flags() & VideoPacket::FIRST_PACKET) != 0); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 87 | } |
| 88 | |
| 89 | if (state_ == kWaitingForRectData) { |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 90 | if (packet->has_data()) { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 91 | ++rect_data_; |
| 92 | } |
| 93 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 94 | if ((packet->flags() & VideoPacket::LAST_PACKET) != 0) { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 95 | // Expect that we have received some data. |
| 96 | EXPECT_GT(rect_data_, 0); |
| 97 | rect_data_ = 0; |
| 98 | state_ = kWaitingForBeginRect; |
| 99 | ++end_rect_; |
| 100 | } |
[email protected] | 5bc7183 | 2010-12-09 01:34:08 | [diff] [blame] | 101 | |
| 102 | if ((packet->flags() & VideoPacket::LAST_PARTITION) != 0) { |
| 103 | // LAST_PARTITION must always be marked with LAST_PACKET. |
| 104 | EXPECT_TRUE((packet->flags() & VideoPacket::LAST_PACKET) != 0); |
| 105 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 106 | } |
| 107 | } |
| 108 | |
| 109 | void set_strict(bool strict) { |
| 110 | strict_ = strict; |
| 111 | } |
| 112 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 113 | void AddRects(const DesktopRect* rects, int count) { |
[email protected] | f301d736 | 2013-06-05 00:02:02 | [diff] [blame] | 114 | region_.AddRects(rects, count); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | private: |
| 118 | enum State { |
| 119 | kWaitingForBeginRect, |
| 120 | kWaitingForRectData, |
| 121 | }; |
| 122 | |
| 123 | int begin_rect_; |
| 124 | int rect_data_; |
| 125 | int end_rect_; |
| 126 | State state_; |
| 127 | bool strict_; |
| 128 | |
[email protected] | f301d736 | 2013-06-05 00:02:02 | [diff] [blame] | 129 | DesktopRegion region_; |
| 130 | DesktopRegion received_region_; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 131 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 132 | DISALLOW_COPY_AND_ASSIGN(VideoEncoderMessageTester); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 133 | }; |
| 134 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 135 | class VideoDecoderTester { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 136 | public: |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 137 | VideoDecoderTester(VideoDecoder* decoder, |
| 138 | const DesktopSize& screen_size, |
| 139 | const DesktopSize& view_size) |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 140 | : screen_size_(screen_size), |
| 141 | view_size_(view_size), |
| 142 | strict_(false), |
[email protected] | a3c1d45 | 2013-08-21 18:51:40 | [diff] [blame^] | 143 | decoder_(decoder), |
| 144 | frame_(NULL) { |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 145 | image_data_.reset(new uint8[ |
| 146 | view_size_.width() * view_size_.height() * kBytesPerPixel]); |
[email protected] | 55d3688e | 2012-02-24 23:05:56 | [diff] [blame] | 147 | EXPECT_TRUE(image_data_.get()); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 148 | decoder_->Initialize( |
| 149 | SkISize::Make(screen_size_.width(), screen_size_.height())); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 150 | } |
| 151 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 152 | void Reset() { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 153 | expected_region_.Clear(); |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 154 | update_region_.setEmpty(); |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 155 | } |
[email protected] | cee5dba | 2010-12-07 03:19:48 | [diff] [blame] | 156 | |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 157 | void ResetRenderedData() { |
| 158 | memset(image_data_.get(), 0, |
| 159 | view_size_.width() * view_size_.height() * kBytesPerPixel); |
| 160 | } |
| 161 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 162 | void ReceivedPacket(VideoPacket* packet) { |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 163 | VideoDecoder::DecodeResult result = decoder_->DecodePacket(packet); |
[email protected] | cee5dba | 2010-12-07 03:19:48 | [diff] [blame] | 164 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 165 | ASSERT_NE(VideoDecoder::DECODE_ERROR, result); |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 166 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 167 | if (result == VideoDecoder::DECODE_DONE) { |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 168 | RenderFrame(); |
[email protected] | cee5dba | 2010-12-07 03:19:48 | [diff] [blame] | 169 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 170 | } |
| 171 | |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 172 | void RenderFrame() { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 173 | decoder_->RenderFrame( |
| 174 | SkISize::Make(view_size_.width(), view_size_.height()), |
| 175 | SkIRect::MakeWH(view_size_.width(), view_size_.height()), |
| 176 | image_data_.get(), |
| 177 | view_size_.width() * kBytesPerPixel, |
| 178 | &update_region_); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 179 | } |
| 180 | |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 181 | void ReceivedScopedPacket(scoped_ptr<VideoPacket> packet) { |
| 182 | ReceivedPacket(packet.get()); |
| 183 | } |
| 184 | |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 185 | void set_strict(bool strict) { |
| 186 | strict_ = strict; |
| 187 | } |
| 188 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 189 | void set_frame(webrtc::DesktopFrame* frame) { |
| 190 | frame_ = frame; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 191 | } |
| 192 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 193 | void AddRects(const DesktopRect* rects, int count) { |
| 194 | for (int i = 0; i < count; ++i) { |
| 195 | expected_region_.AddRect(rects[i]); |
| 196 | } |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 197 | } |
| 198 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 199 | void AddRegion(const webrtc::DesktopRegion& region) { |
| 200 | expected_region_.AddRegion(region); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 201 | } |
| 202 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 203 | void VerifyResults() { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 204 | if (!strict_) |
| 205 | return; |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 206 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 207 | ASSERT_TRUE(frame_); |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 208 | |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 209 | // Test the content of the update region. |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 210 | // |
| 211 | // TODO(sergeyu): Change this to use DesktopRegion when it's capable of |
| 212 | // merging the rectangles. |
| 213 | SkRegion expected_region; |
| 214 | for (webrtc::DesktopRegion::Iterator it(expected_region_); |
| 215 | !it.IsAtEnd(); it.Advance()) { |
| 216 | expected_region.op( |
| 217 | SkIRect::MakeXYWH(it.rect().top(), it.rect().left(), |
| 218 | it.rect().width(), it.rect().height()), |
| 219 | SkRegion::kUnion_Op); |
| 220 | } |
| 221 | EXPECT_EQ(expected_region, update_region_); |
| 222 | |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 223 | for (SkRegion::Iterator i(update_region_); !i.done(); i.next()) { |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 224 | const int stride = view_size_.width() * kBytesPerPixel; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 225 | EXPECT_EQ(stride, frame_->stride()); |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 226 | const int offset = stride * i.rect().top() + |
| 227 | kBytesPerPixel * i.rect().left(); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 228 | const uint8* original = frame_->data() + offset; |
[email protected] | 55d3688e | 2012-02-24 23:05:56 | [diff] [blame] | 229 | const uint8* decoded = image_data_.get() + offset; |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 230 | const int row_size = kBytesPerPixel * i.rect().width(); |
| 231 | for (int y = 0; y < i.rect().height(); ++y) { |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 232 | EXPECT_EQ(0, memcmp(original, decoded, row_size)) |
| 233 | << "Row " << y << " is different"; |
| 234 | original += stride; |
| 235 | decoded += stride; |
| 236 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 237 | } |
| 238 | } |
| 239 | |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 240 | // The error at each pixel is the root mean square of the errors in |
| 241 | // the R, G, and B components, each normalized to [0, 1]. This routine |
| 242 | // checks that the maximum and mean pixel errors do not exceed given limits. |
[email protected] | 8c6d71d | 2012-10-23 21:20:04 | [diff] [blame] | 243 | void VerifyResultsApprox(const uint8* expected_view_data, |
| 244 | double max_error_limit, double mean_error_limit) { |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 245 | double max_error = 0.0; |
| 246 | double sum_error = 0.0; |
| 247 | int error_num = 0; |
| 248 | for (SkRegion::Iterator i(update_region_); !i.done(); i.next()) { |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 249 | const int stride = view_size_.width() * kBytesPerPixel; |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 250 | const int offset = stride * i.rect().top() + |
| 251 | kBytesPerPixel * i.rect().left(); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 252 | const uint8* expected = expected_view_data + offset; |
| 253 | const uint8* actual = image_data_.get() + offset; |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 254 | for (int y = 0; y < i.rect().height(); ++y) { |
| 255 | for (int x = 0; x < i.rect().width(); ++x) { |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 256 | double error = CalculateError(expected, actual); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 257 | max_error = std::max(max_error, error); |
| 258 | sum_error += error; |
| 259 | ++error_num; |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 260 | expected += 4; |
| 261 | actual += 4; |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 262 | } |
| 263 | } |
| 264 | } |
| 265 | EXPECT_LE(max_error, max_error_limit); |
| 266 | double mean_error = sum_error / error_num; |
| 267 | EXPECT_LE(mean_error, mean_error_limit); |
| 268 | LOG(INFO) << "Max error: " << max_error; |
| 269 | LOG(INFO) << "Mean error: " << mean_error; |
| 270 | } |
| 271 | |
| 272 | double CalculateError(const uint8* original, const uint8* decoded) { |
| 273 | double error_sum_squares = 0.0; |
| 274 | for (int i = 0; i < 3; i++) { |
| 275 | double error = static_cast<double>(*original++) - |
| 276 | static_cast<double>(*decoded++); |
| 277 | error /= 255.0; |
| 278 | error_sum_squares += error * error; |
| 279 | } |
| 280 | original++; |
| 281 | decoded++; |
| 282 | return sqrt(error_sum_squares / 3.0); |
| 283 | } |
| 284 | |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 285 | private: |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 286 | DesktopSize screen_size_; |
| 287 | DesktopSize view_size_; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 288 | bool strict_; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 289 | webrtc::DesktopRegion expected_region_; |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 290 | SkRegion update_region_; |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 291 | VideoDecoder* decoder_; |
[email protected] | c84c53d | 2013-04-08 20:13:23 | [diff] [blame] | 292 | scoped_ptr<uint8[]> image_data_; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 293 | webrtc::DesktopFrame* frame_; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 294 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 295 | DISALLOW_COPY_AND_ASSIGN(VideoDecoderTester); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 296 | }; |
| 297 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 298 | // The VideoEncoderTester provides a hook for retrieving the data, and passing |
| 299 | // the message to other subprograms for validaton. |
| 300 | class VideoEncoderTester { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 301 | public: |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 302 | VideoEncoderTester(VideoEncoderMessageTester* message_tester) |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 303 | : message_tester_(message_tester), |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 304 | decoder_tester_(NULL), |
| 305 | data_available_(0) { |
| 306 | } |
| 307 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 308 | ~VideoEncoderTester() { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 309 | EXPECT_GT(data_available_, 0); |
| 310 | } |
| 311 | |
[email protected] | 3361e1f | 2012-03-20 20:31:44 | [diff] [blame] | 312 | void DataAvailable(scoped_ptr<VideoPacket> packet) { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 313 | ++data_available_; |
[email protected] | 3361e1f | 2012-03-20 20:31:44 | [diff] [blame] | 314 | message_tester_->ReceivedPacket(packet.get()); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 315 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 316 | // Send the message to the VideoDecoderTester. |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 317 | if (decoder_tester_) { |
[email protected] | 3361e1f | 2012-03-20 20:31:44 | [diff] [blame] | 318 | decoder_tester_->ReceivedPacket(packet.get()); |
[email protected] | cee5dba | 2010-12-07 03:19:48 | [diff] [blame] | 319 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 320 | } |
| 321 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 322 | void AddRects(const DesktopRect* rects, int count) { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 323 | message_tester_->AddRects(rects, count); |
| 324 | } |
| 325 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 326 | void set_decoder_tester(VideoDecoderTester* decoder_tester) { |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 327 | decoder_tester_ = decoder_tester; |
| 328 | } |
| 329 | |
| 330 | private: |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 331 | VideoEncoderMessageTester* message_tester_; |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 332 | VideoDecoderTester* decoder_tester_; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 333 | int data_available_; |
| 334 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 335 | DISALLOW_COPY_AND_ASSIGN(VideoEncoderTester); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 336 | }; |
| 337 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 338 | scoped_ptr<webrtc::DesktopFrame> PrepareFrame(const DesktopSize& size) { |
| 339 | scoped_ptr<webrtc::DesktopFrame> frame(new webrtc::BasicDesktopFrame(size)); |
[email protected] | 04499fb | 2012-08-25 00:33:50 | [diff] [blame] | 340 | |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 341 | srand(0); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 342 | int memory_size = size.width() * size.height() * kBytesPerPixel; |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 343 | for (int i = 0; i < memory_size; ++i) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 344 | frame->data()[i] = rand() % 256; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 345 | } |
| 346 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 347 | return frame.Pass(); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 348 | } |
| 349 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 350 | static void TestEncodingRects(VideoEncoder* encoder, |
| 351 | VideoEncoderTester* tester, |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 352 | webrtc::DesktopFrame* frame, |
| 353 | const DesktopRect* rects, |
| 354 | int count) { |
| 355 | frame->mutable_updated_region()->Clear(); |
[email protected] | 88552a9 | 2010-08-06 22:50:00 | [diff] [blame] | 356 | for (int i = 0; i < count; ++i) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 357 | frame->mutable_updated_region()->AddRect(rects[i]); |
[email protected] | 88552a9 | 2010-08-06 22:50:00 | [diff] [blame] | 358 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 359 | tester->AddRects(rects, count); |
| 360 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 361 | encoder->Encode(frame, base::Bind( |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 362 | &VideoEncoderTester::DataAvailable, base::Unretained(tester))); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 363 | } |
| 364 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 365 | void TestVideoEncoder(VideoEncoder* encoder, bool strict) { |
[email protected] | 8c6d71d | 2012-10-23 21:20:04 | [diff] [blame] | 366 | const int kSizes[] = {320, 319, 317, 150}; |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 367 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 368 | VideoEncoderMessageTester message_tester; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 369 | message_tester.set_strict(strict); |
| 370 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 371 | VideoEncoderTester tester(&message_tester); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 372 | |
[email protected] | 8c6d71d | 2012-10-23 21:20:04 | [diff] [blame] | 373 | for (size_t xi = 0; xi < arraysize(kSizes); ++xi) { |
| 374 | for (size_t yi = 0; yi < arraysize(kSizes); ++yi) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 375 | DesktopSize size = DesktopSize(kSizes[xi], kSizes[yi]); |
| 376 | scoped_ptr<webrtc::DesktopFrame> frame = PrepareFrame(size); |
| 377 | std::vector<std::vector<DesktopRect> > test_rect_lists = |
[email protected] | 8c6d71d | 2012-10-23 21:20:04 | [diff] [blame] | 378 | MakeTestRectLists(size); |
| 379 | for (size_t i = 0; i < test_rect_lists.size(); ++i) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 380 | const std::vector<DesktopRect>& test_rects = test_rect_lists[i]; |
| 381 | TestEncodingRects(encoder, &tester, frame.get(), |
[email protected] | 8c6d71d | 2012-10-23 21:20:04 | [diff] [blame] | 382 | &test_rects[0], test_rects.size()); |
| 383 | } |
| 384 | } |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 385 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 386 | } |
| 387 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 388 | static void TestEncodeDecodeRects(VideoEncoder* encoder, |
| 389 | VideoEncoderTester* encoder_tester, |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 390 | VideoDecoderTester* decoder_tester, |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 391 | webrtc::DesktopFrame* frame, |
| 392 | const DesktopRect* rects, int count) { |
| 393 | frame->mutable_updated_region()->Clear(); |
| 394 | for (int i = 0; i < count; ++i) { |
| 395 | frame->mutable_updated_region()->AddRect(rects[i]); |
| 396 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 397 | encoder_tester->AddRects(rects, count); |
| 398 | decoder_tester->AddRects(rects, count); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 399 | |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 400 | // Generate random data for the updated region. |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 401 | srand(0); |
| 402 | for (int i = 0; i < count; ++i) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 403 | const int row_size = |
| 404 | webrtc::DesktopFrame::kBytesPerPixel * rects[i].width(); |
| 405 | uint8* memory = frame->data() + |
| 406 | frame->stride() * rects[i].top() + |
| 407 | webrtc::DesktopFrame::kBytesPerPixel * rects[i].left(); |
[email protected] | a9c88d1 | 2012-01-29 03:45:17 | [diff] [blame] | 408 | for (int y = 0; y < rects[i].height(); ++y) { |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 409 | for (int x = 0; x < row_size; ++x) |
| 410 | memory[x] = rand() % 256; |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 411 | memory += frame->stride(); |
[email protected] | 66db1af9 | 2010-07-27 01:42:46 | [diff] [blame] | 412 | } |
| 413 | } |
| 414 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 415 | encoder->Encode(frame, base::Bind(&VideoEncoderTester::DataAvailable, |
| 416 | base::Unretained(encoder_tester))); |
[email protected] | 137e58f1 | 2010-12-07 19:35:43 | [diff] [blame] | 417 | decoder_tester->VerifyResults(); |
| 418 | decoder_tester->Reset(); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 419 | } |
| 420 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 421 | void TestVideoEncoderDecoder( |
| 422 | VideoEncoder* encoder, VideoDecoder* decoder, bool strict) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 423 | DesktopSize kSize = DesktopSize(320, 240); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 424 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 425 | VideoEncoderMessageTester message_tester; |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 426 | message_tester.set_strict(strict); |
| 427 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 428 | VideoEncoderTester encoder_tester(&message_tester); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 429 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 430 | scoped_ptr<webrtc::DesktopFrame> frame = PrepareFrame(kSize); |
[email protected] | dc454a7c | 2011-08-12 22:01:13 | [diff] [blame] | 431 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 432 | VideoDecoderTester decoder_tester(decoder, kSize, kSize); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 433 | decoder_tester.set_strict(strict); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 434 | decoder_tester.set_frame(frame.get()); |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 435 | encoder_tester.set_decoder_tester(&decoder_tester); |
| 436 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 437 | std::vector<std::vector<DesktopRect> > test_rect_lists = |
| 438 | MakeTestRectLists(kSize); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 439 | for (size_t i = 0; i < test_rect_lists.size(); ++i) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 440 | const std::vector<DesktopRect> test_rects = test_rect_lists[i]; |
| 441 | TestEncodeDecodeRects(encoder, &encoder_tester, &decoder_tester, |
| 442 | frame.get(), &test_rects[0], test_rects.size()); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 443 | } |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 444 | } |
| 445 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 446 | static void FillWithGradient(webrtc::DesktopFrame* frame) { |
| 447 | for (int j = 0; j < frame->size().height(); ++j) { |
| 448 | uint8* p = frame->data() + j * frame->stride(); |
| 449 | for (int i = 0; i < frame->size().width(); ++i) { |
| 450 | *p++ = (255.0 * i) / frame->size().width(); |
| 451 | *p++ = (164.0 * j) / frame->size().height(); |
| 452 | *p++ = (82.0 * (i + j)) / |
| 453 | (frame->size().width() + frame->size().height()); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 454 | *p++ = 0; |
| 455 | } |
| 456 | } |
| 457 | } |
| 458 | |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 459 | void TestVideoEncoderDecoderGradient(VideoEncoder* encoder, |
| 460 | VideoDecoder* decoder, |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 461 | const DesktopSize& screen_size, |
| 462 | const DesktopSize& view_size, |
[email protected] | 92b45b8e | 2012-08-24 19:46:47 | [diff] [blame] | 463 | double max_error_limit, |
| 464 | double mean_error_limit) { |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 465 | scoped_ptr<webrtc::BasicDesktopFrame> frame( |
| 466 | new webrtc::BasicDesktopFrame(screen_size)); |
| 467 | FillWithGradient(frame.get()); |
| 468 | frame->mutable_updated_region()->SetRect(DesktopRect::MakeSize(screen_size)); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 469 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 470 | scoped_ptr<webrtc::BasicDesktopFrame> expected_result( |
| 471 | new webrtc::BasicDesktopFrame(view_size)); |
| 472 | FillWithGradient(expected_result.get()); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 473 | |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 474 | VideoDecoderTester decoder_tester(decoder, screen_size, view_size); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 475 | decoder_tester.set_frame(frame.get()); |
| 476 | decoder_tester.AddRegion(frame->updated_region()); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 477 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 478 | encoder->Encode(frame.get(), |
[email protected] | d9004e4 | 2012-08-24 01:47:37 | [diff] [blame] | 479 | base::Bind(&VideoDecoderTester::ReceivedScopedPacket, |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 480 | base::Unretained(&decoder_tester))); |
| 481 | |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 482 | decoder_tester.VerifyResultsApprox(expected_result->data(), |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 483 | max_error_limit, mean_error_limit); |
| 484 | |
| 485 | // Check that the decoder correctly re-renders the frame if its client |
| 486 | // invalidates the frame. |
| 487 | decoder_tester.ResetRenderedData(); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 488 | decoder->Invalidate( |
| 489 | SkISize::Make(view_size.width(), view_size.height()), |
| 490 | SkRegion(SkIRect::MakeWH(view_size.width(), view_size.height()))); |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 491 | decoder_tester.RenderFrame(); |
[email protected] | b9ed58f | 2013-05-16 10:45:24 | [diff] [blame] | 492 | decoder_tester.VerifyResultsApprox(expected_result->data(), |
[email protected] | 1d65f48 | 2012-07-28 06:40:46 | [diff] [blame] | 493 | max_error_limit, mean_error_limit); |
[email protected] | 36b967f | 2012-07-27 18:35:32 | [diff] [blame] | 494 | } |
| 495 | |
[email protected] | fb13c76 | 2010-07-24 02:22:07 | [diff] [blame] | 496 | } // namespace remoting |