Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2623)

Unified Diff: media/blink/multibuffer_reader.cc

Issue 1420883004: Multibuffer reader implementation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@media_cache
Patch Set: iterator fix + speed up random tests 3x Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/blink/multibuffer_reader.h ('k') | media/blink/multibuffer_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/blink/multibuffer_reader.cc
diff --git a/media/blink/multibuffer_reader.cc b/media/blink/multibuffer_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8f98167684c63d98233e1d5cb7e8dfec5cf931fb
--- /dev/null
+++ b/media/blink/multibuffer_reader.cc
@@ -0,0 +1,237 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "media/blink/multibuffer_reader.h"
+#include "net/base/net_errors.h"
+
+namespace media {
+
+MultiBufferReader::MultiBufferReader(
+ MultiBuffer* multibuffer,
+ int64_t start,
+ int64_t end,
+ const base::Callback<void(int64_t, int64_t)>& progress_callback)
+ : multibuffer_(multibuffer),
+ // If end is -1, we use a very large (but still supported) value instead.
+ end_(end == -1LL ? (1LL << (multibuffer->block_size_shift() + 30)) : end),
+ preload_high_(0),
+ preload_low_(0),
+ max_buffer_forward_(0),
+ max_buffer_backward_(0),
+ pos_(start),
+ preload_pos_(-1),
+ loading_(true),
+ current_wait_size_(0),
+ progress_callback_(progress_callback),
+ weak_factory_(this) {
+ DCHECK_GE(start, 0);
+ DCHECK_GE(end_, 0);
+}
+
+MultiBufferReader::~MultiBufferReader() {
+ multibuffer_->RemoveReader(preload_pos_, this);
+ multibuffer_->IncrementMaxSize(
+ -block_ceil(max_buffer_forward_ + max_buffer_backward_));
+ multibuffer_->PinRange(block(pos_ - max_buffer_backward_),
+ block_ceil(pos_ + max_buffer_forward_), -1);
+ multibuffer_->CleanupWriters(preload_pos_);
+}
+
+void MultiBufferReader::Seek(int64_t pos) {
+ DCHECK_GE(pos, 0);
+ if (pos == pos_)
+ return;
+ // Use a rangemap to compute the diff in pinning.
+ IntervalMap<MultiBuffer::BlockId, int32_t> tmp;
+ tmp.IncrementInterval(block(pos_ - max_buffer_backward_),
+ block_ceil(pos_ + max_buffer_forward_), -1);
+ tmp.IncrementInterval(block(pos - max_buffer_backward_),
+ block_ceil(pos + max_buffer_forward_), 1);
+
+ multibuffer_->PinRanges(tmp);
+
+ multibuffer_->RemoveReader(preload_pos_, this);
+ MultiBufferBlockId old_preload_pos = preload_pos_;
+ preload_pos_ = block(pos);
+ pos_ = pos;
+ UpdateInternalState();
+ multibuffer_->CleanupWriters(old_preload_pos);
+}
+
+void MultiBufferReader::SetMaxBuffer(int64_t backward, int64_t forward) {
+ // Safe, because we know this doesn't actually prune the cache right away.
+ multibuffer_->IncrementMaxSize(
+ -block_ceil(max_buffer_forward_ + max_buffer_backward_));
+ // Use a rangemap to compute the diff in pinning.
+ IntervalMap<MultiBuffer::BlockId, int32_t> tmp;
+ tmp.IncrementInterval(block(pos_ - max_buffer_backward_),
+ block_ceil(pos_ + max_buffer_forward_), -1);
+ max_buffer_backward_ = backward;
+ max_buffer_forward_ = forward;
+ tmp.IncrementInterval(block(pos_ - max_buffer_backward_),
+ block_ceil(pos_ + max_buffer_forward_), 1);
+ multibuffer_->PinRanges(tmp);
+
+ multibuffer_->IncrementMaxSize(
+ block_ceil(max_buffer_forward_ + max_buffer_backward_));
+}
+
+int64_t MultiBufferReader::Available() const {
+ int64_t unavailable_byte_pos =
+ static_cast<int64_t>(multibuffer_->FindNextUnavailable(block(pos_)))
+ << multibuffer_->block_size_shift();
+ return std::max<int64_t>(0, unavailable_byte_pos - pos_);
+}
+
+int64_t MultiBufferReader::TryRead(uint8_t* data, int64_t len) {
+ DCHECK_GT(len, 0);
+ current_wait_size_ = 0;
+ cb_.Reset();
+ DCHECK_LE(pos_ + len, end_);
+ const MultiBuffer::DataMap& data_map = multibuffer_->map();
+ MultiBuffer::DataMap::const_iterator i = data_map.find(block(pos_));
+ int64_t p = pos_;
+ int64_t bytes_read = 0;
+ while (bytes_read < len) {
+ if (i == data_map.end())
+ break;
+ if (i->first != block(p))
+ break;
+ if (i->second->end_of_stream())
+ break;
+ size_t offset = p & ((1LL << multibuffer_->block_size_shift()) - 1);
+ size_t tocopy =
+ std::min<size_t>(len - bytes_read, i->second->data_size() - offset);
+ memcpy(data, i->second->data() + offset, tocopy);
+ data += tocopy;
+ bytes_read += tocopy;
+ p += tocopy;
+ ++i;
+ }
+ Seek(p);
+ return bytes_read;
+}
+
+int MultiBufferReader::Wait(int64_t len, const base::Closure& cb) {
+ DCHECK_LE(pos_ + len, end_);
+ DCHECK_NE(Available(), -1);
+ DCHECK_LE(len, max_buffer_forward_);
+ current_wait_size_ = len;
+
+ cb_.Reset();
+ UpdateInternalState();
+
+ if (Available() >= current_wait_size_) {
+ return net::OK;
+ } else {
+ cb_ = cb;
+ return net::ERR_IO_PENDING;
+ }
+}
+
+void MultiBufferReader::SetPreload(int64_t preload_high, int64_t preload_low) {
+ DCHECK_GE(preload_high, preload_low);
+ multibuffer_->RemoveReader(preload_pos_, this);
+ preload_pos_ = block(pos_);
+ preload_high_ = preload_high;
+ preload_low_ = preload_low;
+ UpdateInternalState();
+}
+
+bool MultiBufferReader::IsLoading() const {
+ return loading_;
+}
+
+void MultiBufferReader::CheckWait() {
+ if (!cb_.is_null() &&
+ (Available() >= current_wait_size_ || Available() == -1)) {
+ // We redirect the call through a weak pointer to ourselves to guarantee
+ // there are no callbacks from us after we've been destroyed.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MultiBufferReader::Call, weak_factory_.GetWeakPtr(),
+ base::ResetAndReturn(&cb_)));
+ }
+}
+
+void MultiBufferReader::Call(const base::Closure& cb) const {
+ cb.Run();
+}
+
+void MultiBufferReader::NotifyAvailableRange(
+ const Interval<MultiBufferBlockId>& range) {
+ // Update end_ if we can.
+ if (range.end > range.begin) {
+ auto i = multibuffer_->map().find(range.end - 1);
+ DCHECK(i != multibuffer_->map().end());
+ if (i->second->end_of_stream()) {
+ // This is an upper limit because the last-to-one block is allowed
+ // to be smaller than the rest of the blocks.
+ int64_t size_upper_limit = static_cast<int64_t>(range.end)
+ << multibuffer_->block_size_shift();
+ end_ = std::min(end_, size_upper_limit);
+ }
+ }
+ UpdateInternalState();
+ if (!progress_callback_.is_null()) {
+ // We redirect the call through a weak pointer to ourselves to guarantee
+ // there are no callbacks from us after we've been destroyed.
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&MultiBufferReader::Call, weak_factory_.GetWeakPtr(),
+ base::Bind(progress_callback_,
+ static_cast<int64_t>(range.begin)
+ << multibuffer_->block_size_shift(),
+ static_cast<int64_t>(range.end)
+ << multibuffer_->block_size_shift())));
+ // We may be destroyed, do not touch |this|.
+ }
+}
+
+void MultiBufferReader::UpdateInternalState() {
+ int64_t effective_preload = loading_ ? preload_high_ : preload_low_;
+
+ loading_ = false;
+ if (preload_pos_ == -1) {
+ preload_pos_ = block(pos_);
+ DCHECK_GE(preload_pos_, 0);
+ }
+ MultiBuffer::BlockId max_preload = block_ceil(
+ std::min(end_, pos_ + std::max(effective_preload, current_wait_size_)));
+
+ // Note that we might not have been added to the multibuffer,
+ // removing ourselves is a no-op in that case.
+ multibuffer_->RemoveReader(preload_pos_, this);
+
+ // We explicitly allow preloading to go beyond the pinned region in the cache.
+ // It only happens when we want to preload something into the disk cache.
+ // Thus it is possible to have blocks between our current reading position
+ // and preload_pos_ be unavailable. When we get a Seek() call (possibly
+ // through TryRead()) we reset the preload_pos_ to the current reading
+ // position, and preload_pos_ will become the first unavailable block after
+ // our current reading position again.
+ preload_pos_ = multibuffer_->FindNextUnavailable(preload_pos_);
+ DCHECK_GE(preload_pos_, 0);
+
+ DVLOG(3) << "UpdateInternalState"
+ << " pp = " << preload_pos_
+ << " block_ceil(end_) = " << block_ceil(end_) << " end_ = " << end_
+ << " max_preload " << max_preload;
+
+ if (preload_pos_ < block_ceil(end_)) {
+ if (preload_pos_ < max_preload) {
+ loading_ = true;
+ multibuffer_->AddReader(preload_pos_, this);
+ } else if (multibuffer_->Contains(preload_pos_ - 1)) {
+ --preload_pos_;
+ multibuffer_->AddReader(preload_pos_, this);
+ }
+ }
+ CheckWait();
+}
+
+} // namespace media
« no previous file with comments | « media/blink/multibuffer_reader.h ('k') | media/blink/multibuffer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698