Chromium Code Reviews| 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 "base/bind.h" | |
| 6 #include "base/callback_helpers.h" | |
| 7 #include "base/message_loop/message_loop.h" | |
| 8 #include "media/blink/multibuffer_reader.h" | |
| 9 #include "net/base/net_errors.h" | |
| 10 | |
| 11 namespace media { | |
| 12 | |
| 13 MultiBufferReader::MultiBufferReader( | |
| 14 MultiBuffer* multibuffer, | |
| 15 int64_t start, | |
| 16 int64_t end, | |
| 17 base::Callback<void(int64_t, int64_t)> progress_callback) : | |
| 18 multibuffer_(multibuffer), | |
| 19 end_(end == -1LL ? (1LL << (multibuffer->block_size_shift() + 30)) : end), | |
| 20 preload_high_(0), | |
| 21 preload_low_(0), | |
| 22 max_buffer_forward_(0), | |
| 23 max_buffer_backward_(0), | |
| 24 pos_(start), | |
| 25 preload_pos_(), | |
| 26 loading_(true), | |
| 27 current_wait_size_(0), | |
| 28 progress_callback_(progress_callback), | |
| 29 weak_factory_(this) { | |
| 30 DCHECK_GE(start, 0); | |
| 31 DCHECK_GE(end_, 0); | |
| 32 } | |
| 33 | |
| 34 MultiBufferReader::~MultiBufferReader() { | |
| 35 multibuffer_->RemoveReader(preload_pos_, this); | |
| 36 multibuffer_->IncrementMaxSize( | |
| 37 -block_ceil(max_buffer_forward_ + max_buffer_backward_)); | |
| 38 multibuffer_->PinRange(block(pos_ - max_buffer_backward_), | |
| 39 block_ceil(pos_ + max_buffer_forward_), | |
| 40 -1); | |
| 41 multibuffer_->CleanupWriters(preload_pos_); | |
| 42 } | |
| 43 | |
| 44 MultiBuffer::BlockId MultiBufferReader::block(int64_t byte_pos) const { | |
| 45 return byte_pos >> multibuffer_->block_size_shift(); | |
| 46 } | |
| 47 | |
| 48 MultiBuffer::BlockId MultiBufferReader::block_ceil(int64_t byte_pos) const { | |
| 49 return block(byte_pos + (1LL << multibuffer_->block_size_shift()) - 1); | |
| 50 } | |
| 51 | |
| 52 void MultiBufferReader::Seek(int64_t pos) { | |
| 53 DCHECK_GE(pos, 0); | |
| 54 if (pos == pos_) | |
| 55 return; | |
| 56 // Use a rangemap to compute the diff in pinning. | |
| 57 RangeMap<MultiBuffer::BlockId, int32_t> tmp; | |
| 58 tmp.IncrementRange(block(pos_ - max_buffer_backward_), | |
| 59 block_ceil(pos_ + max_buffer_forward_), | |
| 60 -1); | |
| 61 tmp.IncrementRange(block(pos - max_buffer_backward_), | |
| 62 block_ceil(pos + max_buffer_forward_), | |
| 63 1); | |
| 64 | |
| 65 multibuffer_->PinRanges(tmp); | |
| 66 | |
| 67 multibuffer_->RemoveReader(preload_pos_, this); | |
| 68 MultiBufferBlockId old_preload_pos = preload_pos_; | |
| 69 preload_pos_ = block(pos); | |
| 70 pos_ = pos; | |
| 71 IncrementPreloadPos(); | |
| 72 multibuffer_->CleanupWriters(old_preload_pos); | |
| 73 } | |
| 74 | |
| 75 void MultiBufferReader::SetMaxBuffer(int64_t backward, int64_t forward) { | |
| 76 // Safe, because we know this doesn't actually prune the cache right away. | |
| 77 multibuffer_->IncrementMaxSize( | |
| 78 -block_ceil(max_buffer_forward_ + max_buffer_backward_)); | |
| 79 // Use a rangemap to compute the diff in pinning. | |
| 80 RangeMap<MultiBuffer::BlockId, int32_t> tmp; | |
| 81 tmp.IncrementRange(block(pos_ - max_buffer_backward_), | |
| 82 block_ceil(pos_ + max_buffer_forward_), | |
| 83 -1); | |
| 84 max_buffer_backward_ = backward; | |
| 85 max_buffer_forward_ = forward; | |
| 86 tmp.IncrementRange(block(pos_ - max_buffer_backward_), | |
| 87 block_ceil(pos_ + max_buffer_forward_), | |
| 88 1); | |
| 89 multibuffer_->PinRanges(tmp); | |
| 90 | |
| 91 multibuffer_->IncrementMaxSize( | |
| 92 block_ceil(max_buffer_forward_ + max_buffer_backward_)); | |
| 93 } | |
| 94 | |
| 95 | |
| 96 int64_t MultiBufferReader::Available() const { | |
| 97 MultiBufferBlockId current_block = block(pos_); | |
| 98 int64_t unavailable_byte_pos = | |
| 99 static_cast<int64_t>( | |
| 100 multibuffer_->FindNextUnavailable(block(pos_))) << | |
| 101 multibuffer_->block_size_shift(); | |
| 102 return std::max<int64_t>(0, unavailable_byte_pos - pos_); | |
| 103 } | |
| 104 | |
| 105 int64_t MultiBufferReader::TryRead(unsigned char *data, int64_t len) { | |
| 106 DCHECK_GT(len, 0); | |
| 107 current_wait_size_ = 0; | |
| 108 cb_ = base::Closure(); | |
| 109 DCHECK_LE(pos_ + len, end_); | |
| 110 const MultiBuffer::DataMap& data_map = multibuffer_->map(); | |
| 111 MultiBuffer::DataMap::const_iterator i = data_map.find(block(pos_)); | |
| 112 int64_t p = pos_; | |
| 113 int64_t bytes_read = 0; | |
| 114 while (bytes_read < len) { | |
| 115 if (i == data_map.end()) break; | |
| 116 if (i->first != block(p)) break; | |
| 117 if (i->second->end_of_stream()) break; | |
| 118 size_t offset = p & ((1LL << multibuffer_->block_size_shift()) - 1); | |
| 119 size_t tocopy = std::min<size_t>(len - bytes_read, | |
| 120 i->second->data_size() - offset); | |
| 121 memcpy(data, i->second->data() + offset, tocopy); | |
| 122 data += tocopy; | |
| 123 bytes_read += tocopy; | |
| 124 p += tocopy; | |
| 125 ++i; | |
| 126 } | |
| 127 Seek(p); | |
| 128 return bytes_read; | |
| 129 } | |
| 130 | |
| 131 int MultiBufferReader::Wait(int64_t len, base::Closure cb) { | |
| 132 DCHECK_LE(pos_ + len, end_); | |
| 133 DCHECK_NE(Available(), -1); | |
| 134 DCHECK_LE(len, max_buffer_forward_); | |
| 135 current_wait_size_ = len; | |
| 136 | |
| 137 cb_= base::Closure(); | |
|
DaleCurtis
2015/10/28 23:06:13
Why? cb_.Reset() ?
hubbe
2015/10/29 17:52:44
Done. (Also fixed in TryRead())
| |
| 138 IncrementPreloadPos(); | |
| 139 | |
| 140 if (Available() >= current_wait_size_) { | |
| 141 return net::OK; | |
| 142 } else { | |
| 143 cb_ = cb; | |
| 144 return net::ERR_IO_PENDING; | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 void MultiBufferReader::SetPreload(int64_t preload_high, int64_t preload_low) { | |
| 149 multibuffer_->RemoveReader(preload_pos_, this); | |
| 150 preload_pos_ = block(pos_); | |
| 151 preload_high_ = preload_high; | |
| 152 preload_low_ = preload_low; | |
| 153 IncrementPreloadPos(); | |
| 154 } | |
| 155 | |
| 156 bool MultiBufferReader::IsLoading() const { | |
| 157 return loading_; | |
| 158 } | |
| 159 | |
| 160 void MultiBufferReader::CheckWait() { | |
| 161 if (!cb_.is_null() && (Available() >= current_wait_size_ || | |
| 162 Available() == -1)) { | |
| 163 base::MessageLoop::current()->PostTask( | |
| 164 FROM_HERE, | |
| 165 base::Bind(&MultiBufferReader::Call, weak_factory_.GetWeakPtr(), | |
| 166 base::ResetAndReturn(&cb_))); | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 void MultiBufferReader::Call(const base::Closure& cb) const { | |
|
DaleCurtis
2015/10/28 23:06:13
Should be a way to avoid this by making cb_ a Canc
hubbe
2015/10/29 17:52:44
That doesn't seem like it would be better.
Unless
DaleCurtis
2015/10/29 17:59:05
It'll auto cancel when the member variable goes ou
hubbe
2015/10/29 21:45:06
Interesting, but I'm still not convinced it's bett
| |
| 171 cb.Run(); | |
| 172 } | |
| 173 | |
| 174 void MultiBufferReader::NotifyAvailableRange( | |
| 175 const Range<MultiBufferBlockId>& range) { | |
| 176 // Update end_ if we can. | |
| 177 if (range.end > range.begin) { | |
| 178 auto i = multibuffer_->map().find(range.end - 1); | |
| 179 DCHECK(i != multibuffer_->map().end()); | |
| 180 if (i->second->end_of_stream()) { | |
| 181 // This is an upper limit because the last-to-one block is allowed | |
| 182 // to be smaller than the rest of the blocks. | |
| 183 int64_t size_upper_limit = | |
| 184 static_cast<int64_t>(range.end) << multibuffer_->block_size_shift(); | |
| 185 end_ = std::min(end_, size_upper_limit); | |
| 186 } | |
| 187 } | |
| 188 IncrementPreloadPos(); | |
| 189 if (!progress_callback_.is_null()) { | |
| 190 progress_callback_.Run(static_cast<int64_t>(range.begin) << | |
| 191 multibuffer_->block_size_shift(), | |
| 192 static_cast<int64_t>(range.end) << | |
| 193 multibuffer_->block_size_shift()); | |
| 194 // We may be destroyed, do not touch |this|. | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 void MultiBufferReader::IncrementPreloadPos() { | |
| 199 int64_t effective_preload = loading_ ? preload_high_ : preload_low_; | |
| 200 | |
| 201 loading_ = false; | |
| 202 if (preload_pos_ == MultiBuffer::BlockId()) { | |
| 203 preload_pos_ = block(pos_); | |
| 204 DCHECK_GE(preload_pos_, 0); | |
| 205 } | |
| 206 MultiBuffer::BlockId max_preload = block_ceil( | |
| 207 std::min(end_, pos_ + std::max(effective_preload, current_wait_size_))); | |
| 208 | |
| 209 multibuffer_->RemoveReader(preload_pos_, this); | |
| 210 | |
| 211 preload_pos_ = multibuffer_->FindNextUnavailable(preload_pos_); | |
| 212 DCHECK_GE(preload_pos_, 0); | |
| 213 | |
| 214 DVLOG(3) << "IncrementPreloadPos" | |
| 215 << " pp = " << preload_pos_ | |
| 216 << " block_ceil(end_) = " << block_ceil(end_) | |
| 217 << " end_ = " << end_ | |
| 218 << " max_preload " << max_preload; | |
| 219 | |
| 220 if (preload_pos_ < block_ceil(end_)) { | |
| 221 if (preload_pos_ < max_preload) { | |
| 222 loading_ = true; | |
| 223 multibuffer_->AddReader(preload_pos_, this); | |
| 224 } else if (multibuffer_->Contains(preload_pos_ - 1)) { | |
| 225 --preload_pos_; | |
| 226 multibuffer_->AddReader(preload_pos_, this); | |
| 227 } | |
| 228 } | |
| 229 CheckWait(); | |
| 230 } | |
| 231 | |
| 232 } // namespace media | |
| OLD | NEW |