OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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 <string> |
| 7 #include <vector> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" |
| 11 #include "base/message_loop/message_loop.h" |
| 12 #include "media/blink/multibuffer.h" |
| 13 #include "media/blink/multibuffer_reader.h" |
| 14 #include "media/blink/test_random.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 |
| 17 const int kBlockSizeShift = 8; |
| 18 const size_t kBlockSize = 1UL << kBlockSizeShift; |
| 19 |
| 20 namespace media { |
| 21 class TestMultiBufferDataProvider; |
| 22 |
| 23 std::vector<TestMultiBufferDataProvider*> writers; |
| 24 |
| 25 class TestMultiBufferDataProvider : public media::MultiBuffer::DataProvider { |
| 26 public: |
| 27 TestMultiBufferDataProvider(MultiBufferBlockId pos, |
| 28 size_t file_size, |
| 29 int max_blocks_after_defer, |
| 30 bool must_read_whole_file, |
| 31 media::TestRandom* rnd) |
| 32 : pos_(pos), |
| 33 blocks_until_deferred_(1 << 30), |
| 34 max_blocks_after_defer_(max_blocks_after_defer), |
| 35 file_size_(file_size), |
| 36 must_read_whole_file_(must_read_whole_file), |
| 37 rnd_(rnd) { |
| 38 writers.push_back(this); |
| 39 } |
| 40 |
| 41 ~TestMultiBufferDataProvider() override { |
| 42 if (must_read_whole_file_) { |
| 43 CHECK_GE(pos_ * kBlockSize, file_size_); |
| 44 } |
| 45 for (size_t i = 0; i < writers.size(); i++) { |
| 46 if (writers[i] == this) { |
| 47 writers[i] = writers.back(); |
| 48 writers.pop_back(); |
| 49 return; |
| 50 } |
| 51 } |
| 52 LOG(FATAL) << "Couldn't find myself in writers!"; |
| 53 } |
| 54 |
| 55 MultiBufferBlockId Tell() const override { return pos_; } |
| 56 |
| 57 bool Available() const override { return !fifo_.empty(); } |
| 58 |
| 59 scoped_refptr<DataBuffer> Read() override { |
| 60 DCHECK(Available()); |
| 61 scoped_refptr<DataBuffer> ret = fifo_.front(); |
| 62 fifo_.pop_front(); |
| 63 ++pos_; |
| 64 return ret; |
| 65 } |
| 66 |
| 67 void SetAvailableCallback(const base::Closure& cb) override { |
| 68 DCHECK(!Available()); |
| 69 cb_ = cb; |
| 70 } |
| 71 |
| 72 void SetDeferred(bool deferred) override { |
| 73 if (deferred) { |
| 74 if (max_blocks_after_defer_ > 0) { |
| 75 blocks_until_deferred_ = rnd_->Rand() % max_blocks_after_defer_; |
| 76 } else if (max_blocks_after_defer_ < 0) { |
| 77 blocks_until_deferred_ = -max_blocks_after_defer_; |
| 78 } else { |
| 79 blocks_until_deferred_ = 0; |
| 80 } |
| 81 } else { |
| 82 blocks_until_deferred_ = 1 << 30; |
| 83 } |
| 84 } |
| 85 |
| 86 bool Advance() { |
| 87 if (blocks_until_deferred_ == 0) |
| 88 return false; |
| 89 --blocks_until_deferred_; |
| 90 |
| 91 bool ret = true; |
| 92 scoped_refptr<media::DataBuffer> block = new media::DataBuffer(kBlockSize); |
| 93 size_t x = 0; |
| 94 size_t byte_pos = (fifo_.size() + pos_) * kBlockSize; |
| 95 for (x = 0; x < kBlockSize; x++, byte_pos++) { |
| 96 if (byte_pos >= file_size_) |
| 97 break; |
| 98 block->writable_data()[x] = |
| 99 static_cast<uint8_t>((byte_pos * 15485863) >> 16); |
| 100 } |
| 101 block->set_data_size(static_cast<int>(x)); |
| 102 fifo_.push_back(block); |
| 103 if (byte_pos == file_size_) { |
| 104 fifo_.push_back(DataBuffer::CreateEOSBuffer()); |
| 105 ret = false; |
| 106 } |
| 107 cb_.Run(); |
| 108 return ret; |
| 109 } |
| 110 |
| 111 private: |
| 112 std::deque<scoped_refptr<media::DataBuffer>> fifo_; |
| 113 MultiBufferBlockId pos_; |
| 114 int32_t blocks_until_deferred_; |
| 115 int32_t max_blocks_after_defer_; |
| 116 size_t file_size_; |
| 117 bool must_read_whole_file_; |
| 118 base::Closure cb_; |
| 119 media::TestRandom* rnd_; |
| 120 }; |
| 121 |
| 122 class TestMultiBuffer : public media::MultiBuffer { |
| 123 public: |
| 124 explicit TestMultiBuffer( |
| 125 int32_t shift, |
| 126 const scoped_refptr<media::MultiBuffer::GlobalLRU>& lru, |
| 127 media::TestRandom* rnd) |
| 128 : media::MultiBuffer(shift, lru), |
| 129 range_supported_(false), |
| 130 create_ok_(true), |
| 131 max_writers_(10000), |
| 132 file_size_(1 << 30), |
| 133 max_blocks_after_defer_(0), |
| 134 must_read_whole_file_(false), |
| 135 writers_created_(0), |
| 136 rnd_(rnd) {} |
| 137 |
| 138 void SetMaxWriters(size_t max_writers) { max_writers_ = max_writers; } |
| 139 |
| 140 void CheckPresentState() { |
| 141 IntervalMap<MultiBufferBlockId, int32_t> tmp; |
| 142 for (DataMap::iterator i = data_.begin(); i != data_.end(); ++i) { |
| 143 CHECK(i->second); // Null poineters are not allowed in data_ |
| 144 CHECK_NE(!!pinned_[i->first], lru_->Contains(this, i->first)) |
| 145 << " i->first = " << i->first; |
| 146 tmp.IncrementInterval(i->first, i->first + 1, 1); |
| 147 } |
| 148 IntervalMap<MultiBufferBlockId, int32_t>::const_iterator tmp_iterator = |
| 149 tmp.begin(); |
| 150 IntervalMap<MultiBufferBlockId, int32_t>::const_iterator present_iterator = |
| 151 present_.begin(); |
| 152 while (tmp_iterator != tmp.end() && present_iterator != present_.end()) { |
| 153 EXPECT_EQ(tmp_iterator.interval_begin(), |
| 154 present_iterator.interval_begin()); |
| 155 EXPECT_EQ(tmp_iterator.interval_end(), present_iterator.interval_end()); |
| 156 EXPECT_EQ(tmp_iterator.value(), present_iterator.value()); |
| 157 ++tmp_iterator; |
| 158 ++present_iterator; |
| 159 } |
| 160 EXPECT_TRUE(tmp_iterator == tmp.end()); |
| 161 EXPECT_TRUE(present_iterator == present_.end()); |
| 162 } |
| 163 |
| 164 void CheckLRUState() { |
| 165 for (DataMap::iterator i = data_.begin(); i != data_.end(); ++i) { |
| 166 CHECK(i->second); // Null poineters are not allowed in data_ |
| 167 CHECK_NE(!!pinned_[i->first], lru_->Contains(this, i->first)) |
| 168 << " i->first = " << i->first; |
| 169 CHECK_EQ(1, present_[i->first]) << " i->first = " << i->first; |
| 170 } |
| 171 } |
| 172 |
| 173 void SetFileSize(size_t file_size) { file_size_ = file_size; } |
| 174 |
| 175 void SetMaxBlocksAfterDefer(int32_t max_blocks_after_defer) { |
| 176 max_blocks_after_defer_ = max_blocks_after_defer; |
| 177 } |
| 178 |
| 179 void SetMustReadWholeFile(bool must_read_whole_file) { |
| 180 must_read_whole_file_ = must_read_whole_file; |
| 181 } |
| 182 |
| 183 int32_t writers_created() const { return writers_created_; } |
| 184 |
| 185 void SetRangeSupported(bool supported) { range_supported_ = supported; } |
| 186 |
| 187 protected: |
| 188 DataProvider* CreateWriter(const MultiBufferBlockId& pos) override { |
| 189 DCHECK(create_ok_); |
| 190 writers_created_++; |
| 191 CHECK_LT(writers.size(), max_writers_); |
| 192 return new TestMultiBufferDataProvider( |
| 193 pos, file_size_, max_blocks_after_defer_, must_read_whole_file_, rnd_); |
| 194 } |
| 195 void Prune(size_t max_to_free) override { |
| 196 // Prune should not cause additional writers to be spawned. |
| 197 create_ok_ = false; |
| 198 MultiBuffer::Prune(max_to_free); |
| 199 create_ok_ = true; |
| 200 } |
| 201 |
| 202 bool RangeSupported() const override { return range_supported_; } |
| 203 |
| 204 private: |
| 205 bool range_supported_; |
| 206 bool create_ok_; |
| 207 size_t max_writers_; |
| 208 size_t file_size_; |
| 209 int32_t max_blocks_after_defer_; |
| 210 bool must_read_whole_file_; |
| 211 int32_t writers_created_; |
| 212 media::TestRandom* rnd_; |
| 213 }; |
| 214 } |
| 215 |
| 216 class MultiBufferTest : public testing::Test { |
| 217 public: |
| 218 MultiBufferTest() |
| 219 : rnd_(42), |
| 220 lru_(new media::MultiBuffer::GlobalLRU()), |
| 221 multibuffer_(kBlockSizeShift, lru_, &rnd_) {} |
| 222 |
| 223 void Advance() { |
| 224 CHECK(media::writers.size()); |
| 225 media::writers[rnd_.Rand() % media::writers.size()]->Advance(); |
| 226 } |
| 227 |
| 228 bool AdvanceAll() { |
| 229 bool advanced = false; |
| 230 for (size_t i = 0; i < media::writers.size(); i++) { |
| 231 advanced |= media::writers[i]->Advance(); |
| 232 } |
| 233 multibuffer_.CheckLRUState(); |
| 234 return advanced; |
| 235 } |
| 236 |
| 237 protected: |
| 238 media::TestRandom rnd_; |
| 239 scoped_refptr<media::MultiBuffer::GlobalLRU> lru_; |
| 240 media::TestMultiBuffer multibuffer_; |
| 241 base::MessageLoop message_loop_; |
| 242 }; |
| 243 |
| 244 TEST_F(MultiBufferTest, ReadAll) { |
| 245 multibuffer_.SetMaxWriters(1); |
| 246 size_t pos = 0; |
| 247 size_t end = 10000; |
| 248 multibuffer_.SetFileSize(10000); |
| 249 multibuffer_.SetMustReadWholeFile(true); |
| 250 media::MultiBufferReader reader(&multibuffer_, pos, end, |
| 251 base::Callback<void(int64_t, int64_t)>()); |
| 252 reader.SetMaxBuffer(2000, 5000); |
| 253 reader.SetPreload(1000, 1000); |
| 254 while (pos < end) { |
| 255 unsigned char buffer[27]; |
| 256 buffer[17] = 17; |
| 257 size_t to_read = std::min<size_t>(end - pos, 17); |
| 258 int64_t bytes_read = reader.TryRead(buffer, to_read); |
| 259 if (bytes_read) { |
| 260 EXPECT_EQ(buffer[17], 17); |
| 261 for (int64_t i = 0; i < bytes_read; i++) { |
| 262 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16); |
| 263 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; |
| 264 pos++; |
| 265 } |
| 266 } else { |
| 267 Advance(); |
| 268 } |
| 269 } |
| 270 } |
| 271 |
| 272 TEST_F(MultiBufferTest, ReadAllAdvanceFirst) { |
| 273 multibuffer_.SetMaxWriters(1); |
| 274 size_t pos = 0; |
| 275 size_t end = 10000; |
| 276 multibuffer_.SetFileSize(10000); |
| 277 multibuffer_.SetMustReadWholeFile(true); |
| 278 media::MultiBufferReader reader(&multibuffer_, pos, end, |
| 279 base::Callback<void(int64_t, int64_t)>()); |
| 280 reader.SetMaxBuffer(2000, 5000); |
| 281 reader.SetPreload(1000, 1000); |
| 282 while (pos < end) { |
| 283 unsigned char buffer[27]; |
| 284 buffer[17] = 17; |
| 285 size_t to_read = std::min<size_t>(end - pos, 17); |
| 286 while (AdvanceAll()) |
| 287 ; |
| 288 int64_t bytes = reader.TryRead(buffer, to_read); |
| 289 EXPECT_GT(bytes, 0); |
| 290 EXPECT_EQ(buffer[17], 17); |
| 291 for (int64_t i = 0; i < bytes; i++) { |
| 292 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16); |
| 293 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; |
| 294 pos++; |
| 295 } |
| 296 } |
| 297 } |
| 298 |
| 299 // Checks that if the data provider provides too much data after we told it |
| 300 // to defer, we kill it. |
| 301 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer) { |
| 302 multibuffer_.SetMaxWriters(1); |
| 303 size_t pos = 0; |
| 304 size_t end = 10000; |
| 305 multibuffer_.SetFileSize(10000); |
| 306 multibuffer_.SetMaxBlocksAfterDefer(-10000); |
| 307 multibuffer_.SetRangeSupported(true); |
| 308 media::MultiBufferReader reader(&multibuffer_, pos, end, |
| 309 base::Callback<void(int64_t, int64_t)>()); |
| 310 reader.SetMaxBuffer(2000, 5000); |
| 311 reader.SetPreload(1000, 1000); |
| 312 while (pos < end) { |
| 313 unsigned char buffer[27]; |
| 314 buffer[17] = 17; |
| 315 size_t to_read = std::min<size_t>(end - pos, 17); |
| 316 while (AdvanceAll()) |
| 317 ; |
| 318 int64_t bytes = reader.TryRead(buffer, to_read); |
| 319 EXPECT_GT(bytes, 0); |
| 320 EXPECT_EQ(buffer[17], 17); |
| 321 for (int64_t i = 0; i < bytes; i++) { |
| 322 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16); |
| 323 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; |
| 324 pos++; |
| 325 } |
| 326 } |
| 327 EXPECT_GT(multibuffer_.writers_created(), 1); |
| 328 } |
| 329 |
| 330 // Same as ReadAllAdvanceFirst_NeverDefer, but the url doesn't support |
| 331 // ranges, so we don't destroy it no matter how much data it provides. |
| 332 TEST_F(MultiBufferTest, ReadAllAdvanceFirst_NeverDefer2) { |
| 333 multibuffer_.SetMaxWriters(1); |
| 334 size_t pos = 0; |
| 335 size_t end = 10000; |
| 336 multibuffer_.SetFileSize(10000); |
| 337 multibuffer_.SetMustReadWholeFile(true); |
| 338 multibuffer_.SetMaxBlocksAfterDefer(-10000); |
| 339 media::MultiBufferReader reader(&multibuffer_, pos, end, |
| 340 base::Callback<void(int64_t, int64_t)>()); |
| 341 reader.SetMaxBuffer(2000, 5000); |
| 342 reader.SetPreload(1000, 1000); |
| 343 while (pos < end) { |
| 344 unsigned char buffer[27]; |
| 345 buffer[17] = 17; |
| 346 size_t to_read = std::min<size_t>(end - pos, 17); |
| 347 while (AdvanceAll()) |
| 348 ; |
| 349 int64_t bytes = reader.TryRead(buffer, to_read); |
| 350 EXPECT_GT(bytes, 0); |
| 351 EXPECT_EQ(buffer[17], 17); |
| 352 for (int64_t i = 0; i < bytes; i++) { |
| 353 uint8_t expected = static_cast<uint8_t>((pos * 15485863) >> 16); |
| 354 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; |
| 355 pos++; |
| 356 } |
| 357 } |
| 358 } |
| 359 |
| 360 TEST_F(MultiBufferTest, LRUTest) { |
| 361 int64_t max_size = 17; |
| 362 int64_t current_size = 0; |
| 363 lru_->IncrementMaxSize(max_size); |
| 364 |
| 365 multibuffer_.SetMaxWriters(1); |
| 366 size_t pos = 0; |
| 367 size_t end = 10000; |
| 368 multibuffer_.SetFileSize(10000); |
| 369 media::MultiBufferReader reader(&multibuffer_, pos, end, |
| 370 base::Callback<void(int64_t, int64_t)>()); |
| 371 reader.SetPreload(10000, 10000); |
| 372 // Note, no pinning, all data should end up in LRU. |
| 373 EXPECT_EQ(current_size, lru_->Size()); |
| 374 current_size += max_size; |
| 375 while (AdvanceAll()) |
| 376 ; |
| 377 EXPECT_EQ(current_size, lru_->Size()); |
| 378 lru_->IncrementMaxSize(-max_size); |
| 379 lru_->Prune(3); |
| 380 current_size -= 3; |
| 381 EXPECT_EQ(current_size, lru_->Size()); |
| 382 lru_->Prune(3); |
| 383 current_size -= 3; |
| 384 EXPECT_EQ(current_size, lru_->Size()); |
| 385 lru_->Prune(1000); |
| 386 EXPECT_EQ(0, lru_->Size()); |
| 387 } |
| 388 |
| 389 class ReadHelper { |
| 390 public: |
| 391 ReadHelper(size_t end, |
| 392 size_t max_read_size, |
| 393 media::MultiBuffer* multibuffer, |
| 394 media::TestRandom* rnd) |
| 395 : pos_(0), |
| 396 end_(end), |
| 397 max_read_size_(max_read_size), |
| 398 read_size_(0), |
| 399 rnd_(rnd), |
| 400 reader_(multibuffer, |
| 401 pos_, |
| 402 end_, |
| 403 base::Callback<void(int64_t, int64_t)>()) { |
| 404 reader_.SetMaxBuffer(2000, 5000); |
| 405 reader_.SetPreload(1000, 1000); |
| 406 } |
| 407 |
| 408 bool Read() { |
| 409 if (read_size_ == 0) |
| 410 return true; |
| 411 unsigned char buffer[4096]; |
| 412 CHECK_LE(read_size_, static_cast<int64_t>(sizeof(buffer))); |
| 413 CHECK_EQ(pos_, reader_.Tell()); |
| 414 int64_t bytes_read = reader_.TryRead(buffer, read_size_); |
| 415 if (bytes_read) { |
| 416 for (int64_t i = 0; i < bytes_read; i++) { |
| 417 unsigned char expected = (pos_ * 15485863) >> 16; |
| 418 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos_; |
| 419 pos_++; |
| 420 } |
| 421 CHECK_EQ(pos_, reader_.Tell()); |
| 422 return true; |
| 423 } |
| 424 return false; |
| 425 } |
| 426 |
| 427 void StartRead() { |
| 428 CHECK_EQ(pos_, reader_.Tell()); |
| 429 read_size_ = std::min(1 + rnd_->Rand() % (max_read_size_ - 1), end_ - pos_); |
| 430 if (!Read()) { |
| 431 reader_.Wait(read_size_, |
| 432 base::Bind(&ReadHelper::WaitCB, base::Unretained(this))); |
| 433 } |
| 434 } |
| 435 |
| 436 void WaitCB() { CHECK(Read()); } |
| 437 |
| 438 void Seek() { |
| 439 pos_ = rnd_->Rand() % end_; |
| 440 reader_.Seek(pos_); |
| 441 CHECK_EQ(pos_, reader_.Tell()); |
| 442 } |
| 443 |
| 444 private: |
| 445 int64_t pos_; |
| 446 int64_t end_; |
| 447 int64_t max_read_size_; |
| 448 int64_t read_size_; |
| 449 media::TestRandom* rnd_; |
| 450 media::MultiBufferReader reader_; |
| 451 }; |
| 452 |
| 453 TEST_F(MultiBufferTest, RandomTest) { |
| 454 size_t file_size = 1000000; |
| 455 multibuffer_.SetFileSize(file_size); |
| 456 multibuffer_.SetMaxBlocksAfterDefer(10); |
| 457 std::vector<ReadHelper*> read_helpers; |
| 458 for (size_t i = 0; i < 20; i++) { |
| 459 read_helpers.push_back( |
| 460 new ReadHelper(file_size, 1000, &multibuffer_, &rnd_)); |
| 461 } |
| 462 for (int i = 0; i < 100; i++) { |
| 463 for (int j = 0; j < 100; j++) { |
| 464 if (rnd_.Rand() & 1) { |
| 465 if (!media::writers.empty()) |
| 466 Advance(); |
| 467 } else { |
| 468 size_t j = rnd_.Rand() % read_helpers.size(); |
| 469 if (rnd_.Rand() % 100 < 3) |
| 470 read_helpers[j]->Seek(); |
| 471 read_helpers[j]->StartRead(); |
| 472 } |
| 473 } |
| 474 multibuffer_.CheckLRUState(); |
| 475 } |
| 476 multibuffer_.CheckPresentState(); |
| 477 while (!read_helpers.empty()) { |
| 478 delete read_helpers.back(); |
| 479 read_helpers.pop_back(); |
| 480 } |
| 481 } |
| 482 |
| 483 TEST_F(MultiBufferTest, RandomTest_RangeSupported) { |
| 484 size_t file_size = 1000000; |
| 485 multibuffer_.SetFileSize(file_size); |
| 486 multibuffer_.SetMaxBlocksAfterDefer(10); |
| 487 std::vector<ReadHelper*> read_helpers; |
| 488 multibuffer_.SetRangeSupported(true); |
| 489 for (size_t i = 0; i < 20; i++) { |
| 490 read_helpers.push_back( |
| 491 new ReadHelper(file_size, 1000, &multibuffer_, &rnd_)); |
| 492 } |
| 493 for (int i = 0; i < 100; i++) { |
| 494 for (int j = 0; j < 100; j++) { |
| 495 if (rnd_.Rand() & 1) { |
| 496 if (!media::writers.empty()) |
| 497 Advance(); |
| 498 } else { |
| 499 size_t j = rnd_.Rand() % read_helpers.size(); |
| 500 if (rnd_.Rand() % 100 < 3) |
| 501 read_helpers[j]->Seek(); |
| 502 read_helpers[j]->StartRead(); |
| 503 } |
| 504 } |
| 505 multibuffer_.CheckLRUState(); |
| 506 } |
| 507 multibuffer_.CheckPresentState(); |
| 508 while (!read_helpers.empty()) { |
| 509 delete read_helpers.back(); |
| 510 read_helpers.pop_back(); |
| 511 } |
| 512 } |
OLD | NEW |