| 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 "media/blink/multibuffer.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 |
| 14 const int kBlockSizeShift = 8; |
| 15 const size_t kBlockSize = 1UL << kBlockSizeShift; |
| 16 |
| 17 namespace media { |
| 18 class TestMultiBufferDataProvider; |
| 19 |
| 20 std::vector<TestMultiBufferDataProvider*> writers; |
| 21 |
| 22 class TestMultiBufferDataProvider : public media::MultiBufferDataProvider { |
| 23 public: |
| 24 TestMultiBufferDataProvider(MultiBufferBlockId pos) : |
| 25 pos_(pos), |
| 26 deferred_(false) { |
| 27 writers.push_back(this); |
| 28 } |
| 29 |
| 30 ~TestMultiBufferDataProvider() override { |
| 31 for (size_t i = 0; i < writers.size(); i++) { |
| 32 if (writers[i] == this) { |
| 33 writers[i] = writers.back(); |
| 34 writers.pop_back(); |
| 35 return; |
| 36 } |
| 37 } |
| 38 LOG(FATAL) << "Couldn't find myself in writers!"; |
| 39 } |
| 40 |
| 41 MultiBufferBlockId Tell() const override { |
| 42 return pos_; |
| 43 } |
| 44 |
| 45 bool Available() const override { |
| 46 return !fifo_.empty(); |
| 47 } |
| 48 |
| 49 scoped_refptr<DataBuffer> Read() override { |
| 50 DCHECK(Available()); |
| 51 scoped_refptr<DataBuffer> ret = fifo_.front(); |
| 52 fifo_.pop_front(); |
| 53 ++pos_; |
| 54 return ret; |
| 55 } |
| 56 |
| 57 void SetAvailableCallback(base::Closure cb) override { |
| 58 DCHECK(!Available()); |
| 59 cb_ = cb; |
| 60 } |
| 61 |
| 62 void SetDeferred(bool deferred) override { |
| 63 deferred_ = deferred; |
| 64 } |
| 65 |
| 66 bool Advance() { |
| 67 // TODO(hubbe): simulate that we sometimes get data even |
| 68 // after we're deferred. |
| 69 // TODO(hubbe): Add EOF block. |
| 70 // TODO(hubbe): Let last block be smaller. |
| 71 if (deferred_) return false; |
| 72 |
| 73 scoped_refptr<media::DataBuffer> block = new media::DataBuffer(kBlockSize); |
| 74 for (size_t x = 0; x < kBlockSize; x++) { |
| 75 size_t byte_pos = (pos_.block_num() * kBlockSize) + x; |
| 76 block->writable_data()[x] = (byte_pos * 15485863) >> 16; |
| 77 } |
| 78 block->set_data_size(kBlockSize); |
| 79 fifo_.push_back(block); |
| 80 cb_.Run(); |
| 81 return true; |
| 82 } |
| 83 |
| 84 private: |
| 85 std::deque<scoped_refptr<media::DataBuffer> > fifo_; |
| 86 MultiBufferBlockId pos_; |
| 87 bool deferred_; |
| 88 base::Closure cb_; |
| 89 }; |
| 90 |
| 91 class TestMultiBuffer : public media::MultiBuffer { |
| 92 public: |
| 93 explicit TestMultiBuffer(int32_t shift) : |
| 94 media::MultiBuffer(shift), |
| 95 max_writers_(10000) { |
| 96 } |
| 97 |
| 98 void SetMaxWriters(size_t max_writers) { |
| 99 max_writers_ = max_writers; |
| 100 } |
| 101 |
| 102 void CheckLRUState() { |
| 103 for (DataMap::iterator i = data_.begin(); |
| 104 i != data_.end(); |
| 105 ++i) { |
| 106 CHECK(i->second); // Null poineters are not allowed in data_ |
| 107 CHECK_NE(!!pinned_[i->first], lru_.Contains(i->first)) |
| 108 << " i->first = " << i->first; |
| 109 } |
| 110 } |
| 111 |
| 112 protected: |
| 113 MultiBufferDataProvider* CreateWriter(MultiBufferBlockId pos) override { |
| 114 CHECK_LE(writers.size(), max_writers_); |
| 115 CheckLRUState(); |
| 116 return new TestMultiBufferDataProvider(pos); |
| 117 } |
| 118 private: |
| 119 size_t max_writers_; |
| 120 }; |
| 121 |
| 122 } |
| 123 |
| 124 class MultiBufferTest : public testing::Test { |
| 125 public: |
| 126 MultiBufferTest() : |
| 127 multibuffer_(kBlockSizeShift) { |
| 128 } |
| 129 |
| 130 void Advance() { |
| 131 CHECK(media::writers.size()); |
| 132 media::writers[rand() % media::writers.size()]->Advance(); |
| 133 multibuffer_.CheckLRUState(); |
| 134 } |
| 135 |
| 136 bool AdvanceAll() { |
| 137 bool advanced = false; |
| 138 for (size_t i = 0; i < media::writers.size(); i++) { |
| 139 advanced |= media::writers[i]->Advance(); |
| 140 } |
| 141 multibuffer_.CheckLRUState(); |
| 142 return advanced; |
| 143 } |
| 144 |
| 145 scoped_refptr<media::UrlData> GetUrl() { |
| 146 return url_index_.GetByUrl(GURL("http://x"), media::UrlData::kUnspecified); |
| 147 } |
| 148 |
| 149 protected: |
| 150 media::TestMultiBuffer multibuffer_; |
| 151 media::UrlIndex url_index_; |
| 152 }; |
| 153 |
| 154 TEST_F(MultiBufferTest, ReadAll) { |
| 155 multibuffer_.SetMaxWriters(1); |
| 156 size_t pos = 0; |
| 157 size_t end = 10000; |
| 158 media::MultiBufferReader reader(&multibuffer_, |
| 159 GetUrl(), |
| 160 pos, |
| 161 end, |
| 162 1000, |
| 163 1000, |
| 164 5000, |
| 165 2000, |
| 166 base::Callback<void(int64_t, int64_t)>()); |
| 167 while (pos < end) { |
| 168 unsigned char buffer[27]; |
| 169 buffer[17] = 17; |
| 170 size_t to_read = std::min<size_t>(end - pos, 17); |
| 171 int64 bytes_read = reader.TryRead(buffer, to_read); |
| 172 if (bytes_read) { |
| 173 EXPECT_EQ(buffer[17], 17); |
| 174 for (size_t i = 0; i < bytes_read; i++) { |
| 175 unsigned char expected = (pos * 15485863) >> 16; |
| 176 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; |
| 177 pos++; |
| 178 } |
| 179 } else { |
| 180 Advance(); |
| 181 } |
| 182 } |
| 183 } |
| 184 |
| 185 TEST_F(MultiBufferTest, ReadAllAdvanceFirst) { |
| 186 multibuffer_.SetMaxWriters(1); |
| 187 size_t pos = 0; |
| 188 size_t end = 10000; |
| 189 media::MultiBufferReader reader(&multibuffer_, |
| 190 GetUrl(), |
| 191 pos, |
| 192 end, |
| 193 1000, |
| 194 1000, |
| 195 5000, |
| 196 2000, |
| 197 base::Callback<void(int64_t, int64_t)>()); |
| 198 while (pos < end) { |
| 199 unsigned char buffer[27]; |
| 200 buffer[17] = 17; |
| 201 size_t to_read = std::min<size_t>(end - pos, 17); |
| 202 while (AdvanceAll()); |
| 203 EXPECT_TRUE(reader.TryRead(buffer, to_read)); |
| 204 EXPECT_EQ(buffer[17], 17); |
| 205 for (size_t i = 0; i < to_read; i++) { |
| 206 unsigned char expected = (pos * 15485863) >> 16; |
| 207 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos; |
| 208 pos++; |
| 209 } |
| 210 } |
| 211 } |
| 212 |
| 213 class ReadHelper { |
| 214 public: |
| 215 ReadHelper(scoped_refptr<media::UrlData> url, |
| 216 size_t end, |
| 217 size_t max_read_size, |
| 218 media::MultiBuffer* multibuffer) : |
| 219 pos_(0), |
| 220 end_(end), |
| 221 max_read_size_(max_read_size), |
| 222 read_size_(0), |
| 223 reader_(multibuffer, |
| 224 url, |
| 225 pos_, |
| 226 end_, |
| 227 1000, |
| 228 1000, |
| 229 5000, |
| 230 2000, |
| 231 base::Callback<void(int64_t, int64_t)>()) { |
| 232 } |
| 233 |
| 234 bool Read() { |
| 235 if (read_size_ == 0) return true; |
| 236 unsigned char buffer[read_size_]; |
| 237 CHECK_EQ(pos_, reader_.Tell()); |
| 238 int64 bytes_read = reader_.TryRead(buffer, read_size_); |
| 239 if (bytes_read) { |
| 240 for (size_t i = 0; i < bytes_read; i++) { |
| 241 unsigned char expected = (pos_ * 15485863) >> 16; |
| 242 EXPECT_EQ(expected, buffer[i]) << " pos = " << pos_; |
| 243 pos_++; |
| 244 } |
| 245 CHECK_EQ(pos_, reader_.Tell()); |
| 246 return true; |
| 247 } |
| 248 return false; |
| 249 } |
| 250 |
| 251 void StartRead() { |
| 252 CHECK_EQ(pos_, reader_.Tell()); |
| 253 read_size_ = std::min(1 + rand() % (max_read_size_ - 1), end_ - pos_); |
| 254 if (!Read()) { |
| 255 reader_.Wait(read_size_, |
| 256 base::Bind(&ReadHelper::WaitCB, base::Unretained(this))); |
| 257 } |
| 258 } |
| 259 |
| 260 void WaitCB() { |
| 261 CHECK(Read()); |
| 262 } |
| 263 |
| 264 void Seek() { |
| 265 pos_ = rand() % end_; |
| 266 reader_.Seek(pos_); |
| 267 CHECK_EQ(pos_, reader_.Tell()); |
| 268 } |
| 269 |
| 270 private: |
| 271 size_t pos_; |
| 272 size_t end_; |
| 273 size_t max_read_size_; |
| 274 size_t read_size_; |
| 275 media::MultiBufferReader reader_; |
| 276 }; |
| 277 |
| 278 TEST_F(MultiBufferTest, RandomTest) { |
| 279 std::vector<ReadHelper*> read_helpers; |
| 280 scoped_refptr<media::UrlData> url = GetUrl(); |
| 281 for (size_t i = 0; i < 20; i++) { |
| 282 read_helpers.push_back(new ReadHelper(url, 1000000, 1000, &multibuffer_)); |
| 283 } |
| 284 for (int i = 0; i < 10000; i++) { |
| 285 if (rand() & 1) { |
| 286 if (!media::writers.empty()) Advance(); |
| 287 } else { |
| 288 size_t j = rand() % read_helpers.size(); |
| 289 if (rand() % 100 < 3) { |
| 290 read_helpers[j]->Seek(); |
| 291 multibuffer_.CheckLRUState(); |
| 292 } |
| 293 read_helpers[j]->StartRead(); |
| 294 multibuffer_.CheckLRUState(); |
| 295 } |
| 296 } |
| 297 while (!read_helpers.empty()) { |
| 298 delete read_helpers.back(); |
| 299 read_helpers.pop_back(); |
| 300 } |
| 301 } |
| OLD | NEW |