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