| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <utility> |
| 6 |
| 5 #include "media/blink/multibuffer.h" | 7 #include "media/blink/multibuffer.h" |
| 6 | 8 |
| 7 #include "base/bind.h" | 9 #include "base/bind.h" |
| 8 | 10 |
| 9 namespace media { | 11 namespace media { |
| 10 | 12 |
| 11 // Returns the block ID closest to (but less or equal than) |pos| from |index|. | 13 // Returns the block ID closest to (but less or equal than) |pos| from |index|. |
| 12 template <class T> | 14 template <class T> |
| 13 static MultiBuffer::BlockId ClosestPreviousEntry( | 15 static MultiBuffer::BlockId ClosestPreviousEntry( |
| 14 const std::map<MultiBuffer::BlockId, T>& index, | 16 const std::map<MultiBuffer::BlockId, T>& index, |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 } | 108 } |
| 107 | 109 |
| 108 // | 110 // |
| 109 // MultiBuffer | 111 // MultiBuffer |
| 110 // | 112 // |
| 111 MultiBuffer::MultiBuffer(int32_t block_size_shift, | 113 MultiBuffer::MultiBuffer(int32_t block_size_shift, |
| 112 const scoped_refptr<GlobalLRU>& global_lru) | 114 const scoped_refptr<GlobalLRU>& global_lru) |
| 113 : max_size_(0), block_size_shift_(block_size_shift), lru_(global_lru) {} | 115 : max_size_(0), block_size_shift_(block_size_shift), lru_(global_lru) {} |
| 114 | 116 |
| 115 MultiBuffer::~MultiBuffer() { | 117 MultiBuffer::~MultiBuffer() { |
| 116 // Delete all writers. | |
| 117 for (const auto& i : writer_index_) { | |
| 118 delete i.second; | |
| 119 } | |
| 120 // Remove all blocks from the LRU. | 118 // Remove all blocks from the LRU. |
| 121 for (const auto& i : data_) { | 119 for (const auto& i : data_) { |
| 122 lru_->Remove(this, i.first); | 120 lru_->Remove(this, i.first); |
| 123 } | 121 } |
| 124 lru_->IncrementDataSize(-static_cast<int64_t>(data_.size())); | 122 lru_->IncrementDataSize(-static_cast<int64_t>(data_.size())); |
| 125 lru_->IncrementMaxSize(-max_size_); | 123 lru_->IncrementMaxSize(-max_size_); |
| 126 } | 124 } |
| 127 | 125 |
| 128 void MultiBuffer::AddReader(const BlockId& pos, Reader* reader) { | 126 void MultiBuffer::AddReader(const BlockId& pos, Reader* reader) { |
| 129 std::set<Reader*>* set_of_readers = &readers_[pos]; | 127 std::set<Reader*>* set_of_readers = &readers_[pos]; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 148 closest_block = pos; | 146 closest_block = pos; |
| 149 } else if (i == present_.begin()) { | 147 } else if (i == present_.begin()) { |
| 150 closest_block = -1; | 148 closest_block = -1; |
| 151 } else { | 149 } else { |
| 152 closest_block = i.interval_begin() - 1; | 150 closest_block = i.interval_begin() - 1; |
| 153 } | 151 } |
| 154 | 152 |
| 155 // Make sure that there are no present blocks between the writer and | 153 // Make sure that there are no present blocks between the writer and |
| 156 // the requested position, as that will cause the writer to quit. | 154 // the requested position, as that will cause the writer to quit. |
| 157 if (closest_writer > closest_block) { | 155 if (closest_writer > closest_block) { |
| 158 provider = writer_index_[closest_writer]; | 156 provider = writer_index_[closest_writer].get(); |
| 159 DCHECK(provider); | 157 DCHECK(provider); |
| 160 } | 158 } |
| 161 } | 159 } |
| 162 if (!provider) { | 160 if (!provider) { |
| 163 DCHECK(writer_index_.find(pos) == writer_index_.end()); | 161 DCHECK(writer_index_.find(pos) == writer_index_.end()); |
| 164 provider = writer_index_[pos] = CreateWriter(pos); | 162 writer_index_[pos] = CreateWriter(pos); |
| 165 provider->SetAvailableCallback(base::Bind( | 163 provider = writer_index_[pos].get(); |
| 166 &MultiBuffer::DataProviderEvent, base::Unretained(this), provider)); | |
| 167 } | 164 } |
| 168 provider->SetDeferred(false); | 165 provider->SetDeferred(false); |
| 169 } | 166 } |
| 170 | 167 |
| 171 void MultiBuffer::RemoveReader(const BlockId& pos, Reader* reader) { | 168 void MultiBuffer::RemoveReader(const BlockId& pos, Reader* reader) { |
| 172 auto i = readers_.find(pos); | 169 auto i = readers_.find(pos); |
| 173 if (i == readers_.end()) | 170 if (i == readers_.end()) |
| 174 return; | 171 return; |
| 175 i->second.erase(reader); | 172 i->second.erase(reader); |
| 176 if (i->second.empty()) { | 173 if (i->second.empty()) { |
| 177 readers_.erase(i); | 174 readers_.erase(i); |
| 178 } | 175 } |
| 179 } | 176 } |
| 180 | 177 |
| 181 void MultiBuffer::CleanupWriters(const BlockId& pos) { | 178 void MultiBuffer::CleanupWriters(const BlockId& pos) { |
| 182 BlockId p2 = pos + kMaxWaitForReaderOffset; | 179 BlockId p2 = pos + kMaxWaitForReaderOffset; |
| 183 BlockId closest_writer = ClosestPreviousEntry(writer_index_, p2); | 180 BlockId closest_writer = ClosestPreviousEntry(writer_index_, p2); |
| 184 while (closest_writer > pos - kMaxWaitForWriterOffset) { | 181 while (closest_writer > pos - kMaxWaitForWriterOffset) { |
| 185 DCHECK(writer_index_[closest_writer]); | 182 DCHECK(writer_index_[closest_writer]); |
| 186 DataProviderEvent(writer_index_[closest_writer]); | 183 OnDataProviderEvent(writer_index_[closest_writer].get()); |
| 187 closest_writer = ClosestPreviousEntry(writer_index_, closest_writer - 1); | 184 closest_writer = ClosestPreviousEntry(writer_index_, closest_writer - 1); |
| 188 } | 185 } |
| 189 } | 186 } |
| 190 | 187 |
| 191 bool MultiBuffer::Contains(const BlockId& pos) const { | 188 bool MultiBuffer::Contains(const BlockId& pos) const { |
| 192 DCHECK(present_[pos] == 0 || present_[pos] == 1) | 189 DCHECK(present_[pos] == 0 || present_[pos] == 1) |
| 193 << " pos = " << pos << " present_[pos] " << present_[pos]; | 190 << " pos = " << pos << " present_[pos] " << present_[pos]; |
| 194 DCHECK_EQ(present_[pos], data_.find(pos) != data_.end() ? 1 : 0); | 191 DCHECK_EQ(present_[pos], data_.find(pos) != data_.end() ? 1 : 0); |
| 195 return !!present_[pos]; | 192 return !!present_[pos]; |
| 196 } | 193 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 } | 248 } |
| 252 if (i.interval_end() == freed_range.first.end) { | 249 if (i.interval_end() == freed_range.first.end) { |
| 253 // Notify the following range that it contains fewer blocks. | 250 // Notify the following range that it contains fewer blocks. |
| 254 auto j = i; | 251 auto j = i; |
| 255 ++j; | 252 ++j; |
| 256 DCHECK_EQ(j.value(), 1); | 253 DCHECK_EQ(j.value(), 1); |
| 257 NotifyAvailableRange(j.interval(), j.interval()); | 254 NotifyAvailableRange(j.interval(), j.interval()); |
| 258 } | 255 } |
| 259 } | 256 } |
| 260 } | 257 } |
| 258 if (data_.empty()) |
| 259 OnEmpty(); |
| 261 } | 260 } |
| 262 | 261 |
| 262 void MultiBuffer::OnEmpty() {} |
| 263 |
| 263 void MultiBuffer::AddProvider(scoped_ptr<DataProvider> provider) { | 264 void MultiBuffer::AddProvider(scoped_ptr<DataProvider> provider) { |
| 264 // If there is already a provider in the same location, we delete it. | 265 // If there is already a provider in the same location, we delete it. |
| 265 DCHECK(!provider->Available()); | 266 DCHECK(!provider->Available()); |
| 266 BlockId pos = provider->Tell(); | 267 BlockId pos = provider->Tell(); |
| 267 DataProvider** place = &writer_index_[pos]; | 268 writer_index_[pos] = std::move(provider); |
| 268 DCHECK_NE(*place, provider.get()); | |
| 269 if (*place) | |
| 270 delete *place; | |
| 271 *place = provider.release(); | |
| 272 } | 269 } |
| 273 | 270 |
| 274 scoped_ptr<MultiBuffer::DataProvider> MultiBuffer::RemoveProvider( | 271 scoped_ptr<MultiBuffer::DataProvider> MultiBuffer::RemoveProvider( |
| 275 DataProvider* provider) { | 272 DataProvider* provider) { |
| 276 BlockId pos = provider->Tell(); | 273 BlockId pos = provider->Tell(); |
| 277 DCHECK_EQ(writer_index_[pos], provider); | 274 auto iter = writer_index_.find(pos); |
| 278 writer_index_.erase(pos); | 275 DCHECK(iter != writer_index_.end()); |
| 279 return scoped_ptr<DataProvider>(provider); | 276 DCHECK_EQ(iter->second.get(), provider); |
| 277 scoped_ptr<DataProvider> ret = std::move(iter->second); |
| 278 writer_index_.erase(iter); |
| 279 return ret; |
| 280 } | 280 } |
| 281 | 281 |
| 282 MultiBuffer::ProviderState MultiBuffer::SuggestProviderState( | 282 MultiBuffer::ProviderState MultiBuffer::SuggestProviderState( |
| 283 const BlockId& pos) const { | 283 const BlockId& pos) const { |
| 284 MultiBufferBlockId next_reader_pos = ClosestNextEntry(readers_, pos); | 284 MultiBufferBlockId next_reader_pos = ClosestNextEntry(readers_, pos); |
| 285 if (next_reader_pos != std::numeric_limits<MultiBufferBlockId>::max() && | 285 if (next_reader_pos != std::numeric_limits<MultiBufferBlockId>::max() && |
| 286 (next_reader_pos - pos <= kMaxWaitForWriterOffset || !RangeSupported())) { | 286 (next_reader_pos - pos <= kMaxWaitForWriterOffset || !RangeSupported())) { |
| 287 // Check if there is another writer between us and the next reader. | 287 // Check if there is another writer between us and the next reader. |
| 288 MultiBufferBlockId next_writer_pos = | 288 MultiBufferBlockId next_writer_pos = |
| 289 ClosestNextEntry(writer_index_, pos + 1); | 289 ClosestNextEntry(writer_index_, pos + 1); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 317 if (RangeSupported() && Contains(id)) | 317 if (RangeSupported() && Contains(id)) |
| 318 return true; | 318 return true; |
| 319 | 319 |
| 320 return false; | 320 return false; |
| 321 } | 321 } |
| 322 | 322 |
| 323 void MultiBuffer::Prune(size_t max_to_free) { | 323 void MultiBuffer::Prune(size_t max_to_free) { |
| 324 lru_->Prune(max_to_free); | 324 lru_->Prune(max_to_free); |
| 325 } | 325 } |
| 326 | 326 |
| 327 void MultiBuffer::DataProviderEvent(DataProvider* provider_tmp) { | 327 void MultiBuffer::OnDataProviderEvent(DataProvider* provider_tmp) { |
| 328 scoped_ptr<DataProvider> provider(RemoveProvider(provider_tmp)); | 328 scoped_ptr<DataProvider> provider(RemoveProvider(provider_tmp)); |
| 329 BlockId start_pos = provider->Tell(); | 329 BlockId start_pos = provider->Tell(); |
| 330 BlockId pos = start_pos; | 330 BlockId pos = start_pos; |
| 331 bool eof = false; | 331 bool eof = false; |
| 332 int64_t blocks_before = data_.size(); | 332 int64_t blocks_before = data_.size(); |
| 333 | 333 |
| 334 while (!ProviderCollision(pos) && !eof) { | 334 while (!ProviderCollision(pos) && !eof) { |
| 335 if (!provider->Available()) { | 335 if (!provider->Available()) { |
| 336 AddProvider(provider.Pass()); | 336 AddProvider(std::move(provider)); |
| 337 break; | 337 break; |
| 338 } | 338 } |
| 339 DCHECK_GE(pos, 0); | 339 DCHECK_GE(pos, 0); |
| 340 scoped_refptr<DataBuffer> data = provider->Read(); | 340 scoped_refptr<DataBuffer> data = provider->Read(); |
| 341 data_[pos] = data; | 341 data_[pos] = data; |
| 342 eof = data->end_of_stream(); | 342 eof = data->end_of_stream(); |
| 343 if (!pinned_[pos]) | 343 if (!pinned_[pos]) |
| 344 lru_->Use(this, pos); | 344 lru_->Use(this, pos); |
| 345 ++pos; | 345 ++pos; |
| 346 } | 346 } |
| 347 int64_t blocks_after = data_.size(); | 347 int64_t blocks_after = data_.size(); |
| 348 int64_t blocks_added = blocks_after - blocks_before; | 348 int64_t blocks_added = blocks_after - blocks_before; |
| 349 | 349 |
| 350 if (pos > start_pos) { | 350 if (pos > start_pos) { |
| 351 present_.SetInterval(start_pos, pos, 1); | 351 present_.SetInterval(start_pos, pos, 1); |
| 352 Interval<BlockId> expanded_range = present_.find(start_pos).interval(); | 352 Interval<BlockId> expanded_range = present_.find(start_pos).interval(); |
| 353 NotifyAvailableRange(expanded_range, expanded_range); | 353 NotifyAvailableRange(expanded_range, expanded_range); |
| 354 | 354 |
| 355 lru_->IncrementDataSize(blocks_added); | 355 lru_->IncrementDataSize(blocks_added); |
| 356 Prune(blocks_added * kMaxFreesPerAdd + 1); | 356 Prune(blocks_added * kMaxFreesPerAdd + 1); |
| 357 } | 357 } |
| 358 | 358 |
| 359 // Check that it's still there before we try to delete it. | 359 // Check that it's still there before we try to delete it. |
| 360 // In case of EOF or a collision, we might not have called AddProvider above. | 360 // In case of EOF or a collision, we might not have called AddProvider above. |
| 361 // Even if we did call AddProvider, calling NotifyAvailableRange can cause | 361 // Even if we did call AddProvider, calling NotifyAvailableRange can cause |
| 362 // readers to seek or self-destruct and clean up any associated writers. | 362 // readers to seek or self-destruct and clean up any associated writers. |
| 363 auto i = writer_index_.find(pos); | 363 auto i = writer_index_.find(pos); |
| 364 if (i != writer_index_.end() && i->second == provider_tmp) { | 364 if (i != writer_index_.end() && i->second.get() == provider_tmp) { |
| 365 switch (SuggestProviderState(pos)) { | 365 switch (SuggestProviderState(pos)) { |
| 366 case ProviderStateLoad: | 366 case ProviderStateLoad: |
| 367 // Not sure we actually need to do this | 367 // Not sure we actually need to do this |
| 368 provider_tmp->SetDeferred(false); | 368 provider_tmp->SetDeferred(false); |
| 369 break; | 369 break; |
| 370 case ProviderStateDefer: | 370 case ProviderStateDefer: |
| 371 provider_tmp->SetDeferred(true); | 371 provider_tmp->SetDeferred(true); |
| 372 break; | 372 break; |
| 373 case ProviderStateDead: | 373 case ProviderStateDead: |
| 374 RemoveProvider(provider_tmp); | 374 RemoveProvider(provider_tmp); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 } | 471 } |
| 472 | 472 |
| 473 void MultiBuffer::IncrementMaxSize(int32_t size) { | 473 void MultiBuffer::IncrementMaxSize(int32_t size) { |
| 474 max_size_ += size; | 474 max_size_ += size; |
| 475 lru_->IncrementMaxSize(size); | 475 lru_->IncrementMaxSize(size); |
| 476 DCHECK_GE(max_size_, 0); | 476 DCHECK_GE(max_size_, 0); |
| 477 // Pruning only happens when blocks are added. | 477 // Pruning only happens when blocks are added. |
| 478 } | 478 } |
| 479 | 479 |
| 480 } // namespace media | 480 } // namespace media |
| OLD | NEW |