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/callback_helpers.h" | |
6 #include "media/blink/multibuffer_reader.h" | |
7 #include "net/base/net_errors.h" | |
8 | |
9 namespace media { | |
10 | |
11 MultiBufferReader::MultiBufferReader( | |
12 MultiBuffer* multibuffer, | |
13 MultiBufferUrlData url_data, | |
14 int64_t start, | |
15 int64_t end, | |
16 base::Callback<void(int64_t, int64_t)> progress_callback) : | |
17 multibuffer_(multibuffer), | |
18 url_data_(url_data), | |
19 end_(end == -1LL ? (1LL << (multibuffer->block_size_shift() + 30)) : end), | |
20 preload_high_(0), | |
21 preload_low_(), | |
liberato (no reviews please)
2015/10/14 14:51:34
(0)?
hubbe
2015/10/16 00:17:43
Done.
| |
22 preload_pos_(), | |
23 loading_(true), | |
24 max_buffer_forward_(0), | |
25 max_buffer_backward_(0), | |
26 pos_(start), | |
27 progress_callback_(progress_callback), | |
28 current_wait_size_(0), | |
29 clear_on_delete_(nullptr) { | |
30 DCHECK_GE(start, 0); | |
31 DCHECK_GE(end_, 0); | |
32 } | |
33 | |
34 MultiBufferReader::~MultiBufferReader() { | |
35 if (clear_on_delete_) *clear_on_delete_ = false; | |
36 multibuffer_->RemoveReader(preload_pos_, this); | |
37 multibuffer_->IncrementMaxSize( | |
38 -block_ceil(max_buffer_forward_ + max_buffer_backward_).block_num()); | |
39 multibuffer_->PinRange(block(pos_ - max_buffer_backward_), | |
40 block_ceil(pos_ + max_buffer_forward_), | |
41 -1); | |
42 multibuffer_->CleanupWriters(preload_pos_); | |
43 } | |
44 | |
45 MultiBuffer::BlockId MultiBufferReader::block(int64_t byte_pos) const { | |
46 return MultiBufferBlockId( | |
47 url_data_, | |
48 byte_pos >> multibuffer_->block_size_shift()); | |
49 } | |
50 | |
51 MultiBuffer::BlockId MultiBufferReader::block_ceil(int64_t byte_pos) const { | |
52 return block(byte_pos + (1LL << multibuffer_->block_size_shift()) - 1); | |
53 } | |
54 | |
55 void MultiBufferReader::Seek(int64_t pos) { | |
56 DCHECK_GE(pos, 0); | |
57 // Use a rangemap to compute the diff in pinning. | |
58 RangeMap<MultiBuffer::BlockId, int32_t> tmp; | |
59 tmp.IncrementRange(block(pos_ - max_buffer_backward_), | |
60 block_ceil(pos_ + max_buffer_forward_), | |
61 -1); | |
62 tmp.IncrementRange(block(pos - max_buffer_backward_), | |
63 block_ceil(pos + max_buffer_forward_), | |
64 1); | |
65 | |
66 multibuffer_->PinRanges(tmp); | |
67 | |
68 multibuffer_->RemoveReader(preload_pos_, this); | |
69 MultiBufferBlockId old_preload_pos = preload_pos_; | |
70 preload_pos_ = block(pos); | |
71 pos_ = pos; | |
72 if (IncrementPreloadPos()) { | |
73 multibuffer_->CleanupWriters(old_preload_pos); | |
74 } | |
75 } | |
76 | |
77 void MultiBufferReader::SetMaxBuffer(int64_t backward, int64_t forward) { | |
78 // Safe, because we know this doesn't actually prune the cache right away. | |
79 multibuffer_->IncrementMaxSize( | |
80 -block_ceil(max_buffer_forward_ + max_buffer_backward_).block_num()); | |
81 // Use a rangemap to compute the diff in pinning. | |
82 RangeMap<MultiBuffer::BlockId, int32_t> tmp; | |
83 tmp.IncrementRange(block(pos_ - max_buffer_backward_), | |
84 block_ceil(pos_ + max_buffer_forward_), | |
85 -1); | |
86 max_buffer_backward_ = backward; | |
87 max_buffer_forward_ = forward; | |
88 tmp.IncrementRange(block(pos_ - max_buffer_backward_), | |
89 block_ceil(pos_ + max_buffer_forward_), | |
90 1); | |
91 multibuffer_->PinRanges(tmp); | |
92 | |
93 multibuffer_->IncrementMaxSize( | |
94 block_ceil(max_buffer_forward_ + max_buffer_backward_).block_num()); | |
95 } | |
96 | |
97 | |
98 int64_t MultiBufferReader::Available() const { | |
99 if (url_data_ == kUnknownUrlData) | |
100 return -1; | |
101 | |
102 MultiBufferBlockId current_block = block(pos_); | |
103 int64_t unavailable_byte_pos = | |
104 static_cast<int64_t>( | |
105 multibuffer_->FindNextUnavailable(block(pos_)).block_num()) << | |
106 multibuffer_->block_size_shift(); | |
107 return std::max<int64_t>(0, unavailable_byte_pos - pos_); | |
108 } | |
109 | |
110 int64_t MultiBufferReader::TryRead(unsigned char *data, int64_t len) { | |
111 DCHECK_GT(len, 0); | |
112 current_wait_size_ = 0; | |
113 cb_ = base::Closure(); | |
114 DCHECK_LE(pos_ + len, end_); | |
115 const MultiBuffer::DataMap& data_map = multibuffer_->map(); | |
116 MultiBuffer::DataMap::const_iterator i = data_map.find(block(pos_)); | |
117 int64_t p = pos_; | |
118 int64_t bytes_read = 0; | |
119 while (bytes_read < len) { | |
120 if (i == data_map.end()) break; | |
121 if (i->first != block(p)) break; | |
122 if (i->second->end_of_stream()) break; | |
123 size_t offset = p & ((1LL << multibuffer_->block_size_shift()) - 1); | |
124 size_t tocopy = std::min<size_t>(len - bytes_read, | |
125 i->second->data_size() - offset); | |
126 memcpy(data, i->second->data() + offset, tocopy); | |
127 data += tocopy; | |
128 bytes_read += tocopy; | |
129 p += tocopy; | |
130 ++i; | |
131 } | |
132 Seek(p); | |
133 return bytes_read; | |
134 } | |
135 | |
136 int MultiBufferReader::Wait(int64_t len, base::Closure cb) { | |
137 DCHECK_LE(pos_ + len, end_); | |
138 DCHECK_NE(Available(), -1); | |
139 DCHECK_LE(len, max_buffer_forward_); | |
140 current_wait_size_ = len; | |
141 IncrementPreloadPos(); | |
liberato (no reviews please)
2015/10/14 14:51:34
check return?
hubbe
2015/10/16 00:17:43
Done.
| |
142 if (Available() >= current_wait_size_) { | |
143 return net::OK; | |
144 } else { | |
145 cb_ = cb; | |
146 return net::ERR_IO_PENDING; | |
147 } | |
148 } | |
149 | |
150 void MultiBufferReader::UpdateUrlData(const MultiBufferUrlData& old_url_data, | |
151 const MultiBufferUrlData& new_url_data) { | |
152 DCHECK_EQ(old_url_data, url_data_); | |
153 multibuffer_->RemoveReader(preload_pos_, this); | |
154 multibuffer_->PinRange(block(pos_ - max_buffer_backward_), | |
155 block_ceil(pos_ + max_buffer_forward_), | |
156 1); | |
157 url_data_ = new_url_data; | |
158 if (url_data_ != kUnknownUrlData) | |
159 multibuffer_->PinRange(block(pos_ - max_buffer_backward_), | |
160 block_ceil(pos_ + max_buffer_forward_), | |
161 1); | |
162 | |
163 MultiBufferBlockId old_preload_pos = preload_pos_; | |
164 multibuffer_->CleanupWriters(old_preload_pos); | |
165 | |
166 preload_pos_ = block(pos_); | |
167 if (IncrementPreloadPos()) { | |
168 if (!progress_callback_.is_null()) { | |
169 MultiBuffer::BlockId unavailable_pos = | |
170 multibuffer_->FindNextUnavailable(preload_pos_); | |
171 progress_callback_.Run( | |
172 pos_, | |
173 static_cast<int64_t>(unavailable_pos.block_num()) << | |
174 multibuffer_->block_size_shift()); | |
175 } | |
176 } | |
177 } | |
178 | |
179 void MultiBufferReader::SetPreload(int64_t preload_high, int64_t preload_low) { | |
180 multibuffer_->RemoveReader(preload_pos_, this); | |
181 preload_pos_ = block(pos_); | |
182 preload_high_ = preload_high; | |
183 preload_low_ = preload_low; | |
184 IncrementPreloadPos(); | |
185 } | |
186 | |
187 bool MultiBufferReader::IsLoading() const { | |
188 return loading_; | |
189 } | |
190 | |
191 bool MultiBufferReader::CheckWait() { | |
192 if (!cb_.is_null() && (Available() >= current_wait_size_ || | |
193 Available() == -1)) { | |
194 current_wait_size_ = 0; | |
195 bool still_alive = true; | |
196 clear_on_delete_ = &still_alive; | |
197 base::ResetAndReturn(&cb_).Run(); | |
198 if (still_alive) { | |
199 clear_on_delete_ = NULL; | |
200 } else { | |
201 return false; | |
liberato (no reviews please)
2015/10/14 14:51:34
super nitpicky: "return false else fall through to
hubbe
2015/10/16 00:17:43
Done.
| |
202 } | |
203 } | |
204 return true; | |
205 } | |
206 | |
207 void MultiBufferReader::NotifyAvailableRange( | |
208 const Range<MultiBufferBlockId>& range) { | |
209 // Update end_ if we can. | |
210 if (range.end > range.begin) { | |
211 auto i = multibuffer_->map().find(range.end - 1); | |
212 DCHECK(i != multibuffer_->map().end()); | |
213 if (i->second->end_of_stream()) { | |
214 // This is an upper limit because the last-to-one block is allowed | |
215 // to be smaller than the rest of the blocks. | |
216 int64_t size_upper_limit = | |
217 static_cast<int64_t>(range.end.block_num()) << | |
218 multibuffer_->block_size_shift(); | |
219 end_ = std::min(end_, size_upper_limit); | |
220 } | |
221 } | |
222 if (IncrementPreloadPos()) { | |
223 if (!progress_callback_.is_null()) { | |
224 progress_callback_.Run(static_cast<int64_t>(range.begin.block_num()) << | |
225 multibuffer_->block_size_shift(), | |
226 static_cast<int64_t>(range.end.block_num()) << | |
227 multibuffer_->block_size_shift()); | |
228 } | |
229 } | |
230 } | |
231 | |
232 bool MultiBufferReader::IncrementPreloadPos() { | |
233 int64_t effective_preload = loading_ ? preload_high_ : preload_low_; | |
234 | |
235 loading_ = false; | |
236 if (url_data_ != kUnknownUrlData) { | |
237 if (preload_pos_ == MultiBuffer::BlockId()) { | |
238 preload_pos_ = block(pos_); | |
239 DCHECK_GE(preload_pos_.block_num(), 0); | |
240 } | |
241 MultiBuffer::BlockId max_preload = block_ceil( | |
242 std::min(end_, pos_ + std::max(effective_preload, current_wait_size_))); | |
243 | |
244 multibuffer_->RemoveReader(preload_pos_, this); | |
245 | |
246 preload_pos_ = multibuffer_->FindNextUnavailable(preload_pos_); | |
247 DCHECK_GE(preload_pos_.block_num(), 0); | |
248 | |
249 DVLOG(3) << "IncrementPreloadPos" | |
250 << " pp = " << preload_pos_ | |
251 << " block_ceil(end_) = " << block_ceil(end_) | |
252 << " end_ = " << end_ | |
253 << " max_preload " << max_preload; | |
254 | |
255 if (preload_pos_ < block_ceil(end_)) { | |
256 if (preload_pos_ < max_preload) { | |
257 loading_ = true; | |
258 multibuffer_->AddReader(preload_pos_, this); | |
259 } else if (multibuffer_->Contains(preload_pos_ - 1)) { | |
260 --preload_pos_; | |
261 multibuffer_->AddReader(preload_pos_, this); | |
262 } | |
263 } | |
264 } | |
265 return CheckWait(); | |
266 } | |
267 | |
268 } // namespace media | |
OLD | NEW |