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

Side by Side Diff: media/blink/buffered_resource_loader.cc

Issue 2272163002: Delete now deprecated BufferedDataSource and friends. (Closed)
Patch Set: Delete BufferedResourceLoader too. Created 4 years, 3 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 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 "media/blink/buffered_resource_loader.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <limits>
10 #include <utility>
11
12 #include "base/bits.h"
13 #include "base/callback_helpers.h"
14 #include "base/metrics/histogram.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "media/base/media_log.h"
18 #include "media/blink/cache_util.h"
19 #include "net/http/http_byte_range.h"
20 #include "net/http/http_request_headers.h"
21 #include "third_party/WebKit/public/platform/WebString.h"
22 #include "third_party/WebKit/public/platform/WebURLError.h"
23 #include "third_party/WebKit/public/platform/WebURLResponse.h"
24 #include "third_party/WebKit/public/web/WebKit.h"
25 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
26
27 using blink::WebFrame;
28 using blink::WebString;
29 using blink::WebURLError;
30 using blink::WebURLLoader;
31 using blink::WebURLLoaderOptions;
32 using blink::WebURLRequest;
33 using blink::WebURLResponse;
34
35 namespace media {
36
37 static const int kHttpOK = 200;
38 static const int kHttpPartialContent = 206;
39
40 // Define the number of bytes in a megabyte.
41 static const int kMegabyte = 1024 * 1024;
42
43 // Minimum capacity of the buffer in forward or backward direction.
44 //
45 // 2MB is an arbitrary limit; it just seems to be "good enough" in practice.
46 static const int kMinBufferCapacity = 2 * kMegabyte;
47
48 // Maximum capacity of the buffer in forward or backward direction. This is
49 // effectively the largest single read the code path can handle.
50 // 20MB is an arbitrary limit; it just seems to be "good enough" in practice.
51 static const int kMaxBufferCapacity = 20 * kMegabyte;
52
53 // Maximum number of bytes outside the buffer we will wait for in order to
54 // fulfill a read. If a read starts more than 2MB away from the data we
55 // currently have in the buffer, we will not wait for buffer to reach the read's
56 // location and will instead reset the request.
57 static const int kForwardWaitThreshold = 2 * kMegabyte;
58
59 // Computes the suggested backward and forward capacity for the buffer
60 // if one wants to play at |playback_rate| * the natural playback speed.
61 // Use a value of 0 for |bitrate| if it is unknown.
62 static void ComputeTargetBufferWindow(double playback_rate, int bitrate,
63 int* out_backward_capacity,
64 int* out_forward_capacity) {
65 static const int kDefaultBitrate = 200 * 1024 * 8; // 200 Kbps.
66 static const int kMaxBitrate = 20 * kMegabyte * 8; // 20 Mbps.
67 static const double kMaxPlaybackRate = 25.0;
68 static const int kTargetSecondsBufferedAhead = 10;
69 static const int kTargetSecondsBufferedBehind = 2;
70
71 // Use a default bit rate if unknown and clamp to prevent overflow.
72 if (bitrate <= 0)
73 bitrate = kDefaultBitrate;
74 bitrate = std::min(bitrate, kMaxBitrate);
75
76 // Only scale the buffer window for playback rates greater than 1.0 in
77 // magnitude and clamp to prevent overflow.
78 bool backward_playback = false;
79 if (playback_rate < 0.0) {
80 backward_playback = true;
81 playback_rate *= -1.0;
82 }
83
84 playback_rate = std::max(playback_rate, 1.0);
85 playback_rate = std::min(playback_rate, kMaxPlaybackRate);
86
87 int bytes_per_second = (bitrate / 8.0) * playback_rate;
88
89 // Clamp between kMinBufferCapacity and kMaxBufferCapacity.
90 *out_forward_capacity = std::max(
91 kTargetSecondsBufferedAhead * bytes_per_second, kMinBufferCapacity);
92 *out_backward_capacity = std::max(
93 kTargetSecondsBufferedBehind * bytes_per_second, kMinBufferCapacity);
94
95 *out_forward_capacity = std::min(*out_forward_capacity, kMaxBufferCapacity);
96 *out_backward_capacity = std::min(*out_backward_capacity, kMaxBufferCapacity);
97
98 if (backward_playback)
99 std::swap(*out_forward_capacity, *out_backward_capacity);
100 }
101
102 BufferedResourceLoader::BufferedResourceLoader(const GURL& url,
103 CORSMode cors_mode,
104 int64_t first_byte_position,
105 int64_t last_byte_position,
106 DeferStrategy strategy,
107 int bitrate,
108 double playback_rate,
109 MediaLog* media_log)
110 : buffer_(kMinBufferCapacity, kMinBufferCapacity),
111 loader_failed_(false),
112 defer_strategy_(strategy),
113 might_be_reused_from_cache_in_future_(true),
114 range_supported_(false),
115 saved_forward_capacity_(0),
116 url_(url),
117 cors_mode_(cors_mode),
118 first_byte_position_(first_byte_position),
119 last_byte_position_(last_byte_position),
120 single_origin_(true),
121 offset_(0),
122 content_length_(kPositionNotSpecified),
123 instance_size_(kPositionNotSpecified),
124 read_position_(0),
125 read_size_(0),
126 read_buffer_(NULL),
127 first_offset_(0),
128 last_offset_(0),
129 bitrate_(bitrate),
130 playback_rate_(playback_rate),
131 media_log_(media_log),
132 cancel_upon_deferral_(false) {
133 // Set the initial capacity of |buffer_| based on |bitrate_| and
134 // |playback_rate_|.
135 UpdateBufferWindow();
136 }
137
138 BufferedResourceLoader::~BufferedResourceLoader() {}
139
140 void BufferedResourceLoader::Start(
141 const StartCB& start_cb,
142 const LoadingStateChangedCB& loading_cb,
143 const ProgressCB& progress_cb,
144 WebFrame* frame) {
145 // Make sure we have not started.
146 DCHECK(start_cb_.is_null());
147 DCHECK(loading_cb_.is_null());
148 DCHECK(progress_cb_.is_null());
149 DCHECK(!start_cb.is_null());
150 DCHECK(!loading_cb.is_null());
151 DCHECK(!progress_cb.is_null());
152 CHECK(frame);
153
154 start_cb_ = start_cb;
155 loading_cb_ = loading_cb;
156 progress_cb_ = progress_cb;
157
158 if (first_byte_position_ != kPositionNotSpecified) {
159 // TODO(hclam): server may not support range request so |offset_| may not
160 // equal to |first_byte_position_|.
161 offset_ = first_byte_position_;
162 }
163
164 // Prepare the request.
165 WebURLRequest request(url_);
166 // TODO(mkwst): Split this into video/audio.
167 request.setRequestContext(WebURLRequest::RequestContextVideo);
168
169 if (IsRangeRequest()) {
170 request.setHTTPHeaderField(
171 WebString::fromUTF8(net::HttpRequestHeaders::kRange),
172 WebString::fromUTF8(net::HttpByteRange::Bounded(
173 first_byte_position_, last_byte_position_).GetHeaderValue()));
174 }
175
176 frame->setReferrerForRequest(request, blink::WebURL());
177
178 // Disable compression, compression for audio/video doesn't make sense...
179 request.setHTTPHeaderField(
180 WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding),
181 WebString::fromUTF8("identity;q=1, *;q=0"));
182
183 // Check for our test WebURLLoader.
184 std::unique_ptr<WebURLLoader> loader;
185 if (test_loader_) {
186 loader = std::move(test_loader_);
187 } else {
188 WebURLLoaderOptions options;
189 if (cors_mode_ == kUnspecified) {
190 options.allowCredentials = true;
191 options.crossOriginRequestPolicy =
192 WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
193 } else {
194 options.exposeAllResponseHeaders = true;
195 // The author header set is empty, no preflight should go ahead.
196 options.preflightPolicy = WebURLLoaderOptions::PreventPreflight;
197 options.crossOriginRequestPolicy =
198 WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
199 if (cors_mode_ == kUseCredentials)
200 options.allowCredentials = true;
201 }
202 loader.reset(frame->createAssociatedURLLoader(options));
203 }
204
205 // Start the resource loading.
206 loader->loadAsynchronously(request, this);
207 active_loader_.reset(new ActiveLoader(std::move(loader)));
208 loading_cb_.Run(kLoading);
209 }
210
211 void BufferedResourceLoader::Stop() {
212 // Reset callbacks.
213 start_cb_.Reset();
214 loading_cb_.Reset();
215 progress_cb_.Reset();
216 read_cb_.Reset();
217
218 // Cancel and reset any active loaders.
219 active_loader_.reset();
220 }
221
222 void BufferedResourceLoader::Read(int64_t position,
223 int read_size,
224 uint8_t* buffer,
225 const ReadCB& read_cb) {
226 DCHECK(start_cb_.is_null());
227 DCHECK(read_cb_.is_null());
228 DCHECK(!read_cb.is_null());
229 DCHECK(buffer);
230 DCHECK_GT(read_size, 0);
231
232 // Save the parameter of reading.
233 read_cb_ = read_cb;
234 read_position_ = position;
235 read_size_ = read_size;
236 read_buffer_ = buffer;
237
238 // Reads should immediately fail if the loader also failed.
239 if (loader_failed_) {
240 DoneRead(kFailed, 0);
241 return;
242 }
243
244 // If we're attempting to read past the end of the file, return a zero
245 // indicating EOF.
246 //
247 // This can happen with callees that read in fixed-sized amounts for parsing
248 // or at the end of chunked 200 responses when we discover the actual length
249 // of the file.
250 if (instance_size_ != kPositionNotSpecified &&
251 instance_size_ <= read_position_) {
252 DVLOG(1) << "Appear to have seeked beyond EOS; returning 0.";
253 DoneRead(kOk, 0);
254 return;
255 }
256
257 // Make sure |offset_| and |read_position_| does not differ by a large
258 // amount.
259 if (read_position_ > offset_ + std::numeric_limits<int32_t>::max() ||
260 read_position_ < offset_ + std::numeric_limits<int32_t>::min()) {
261 DoneRead(kCacheMiss, 0);
262 return;
263 }
264
265 // Make sure |read_size_| is not too large for the buffer to ever be able to
266 // fulfill the read request.
267 if (read_size_ > kMaxBufferCapacity) {
268 DoneRead(kFailed, 0);
269 return;
270 }
271
272 // Prepare the parameters.
273 first_offset_ = read_position_ - offset_;
274 last_offset_ = first_offset_ + read_size_;
275
276 // If we can serve the request now, do the actual read.
277 if (CanFulfillRead()) {
278 ReadInternal();
279 UpdateDeferBehavior();
280 return;
281 }
282
283 // If we expect the read request to be fulfilled later, expand capacity as
284 // necessary and disable deferring.
285 if (WillFulfillRead()) {
286 // Advance offset as much as possible to create additional capacity.
287 int advance = std::min(first_offset_, buffer_.forward_bytes());
288 bool ret = buffer_.Seek(advance);
289 DCHECK(ret);
290
291 offset_ += advance;
292 first_offset_ -= advance;
293 last_offset_ -= advance;
294
295 // Expand capacity to accomodate a read that extends past the normal
296 // capacity.
297 //
298 // This can happen when reading in a large seek index or when the
299 // first byte of a read request falls within kForwardWaitThreshold.
300 if (last_offset_ > buffer_.forward_capacity()) {
301 saved_forward_capacity_ = buffer_.forward_capacity();
302 buffer_.set_forward_capacity(last_offset_);
303 }
304
305 // Make sure we stop deferring now that there's additional capacity.
306 DCHECK(!ShouldDefer())
307 << "Capacity was not adjusted properly to prevent deferring.";
308 UpdateDeferBehavior();
309
310 return;
311 }
312
313 // Make a callback to report failure.
314 DoneRead(kCacheMiss, 0);
315 }
316
317 int64_t BufferedResourceLoader::content_length() {
318 return content_length_;
319 }
320
321 int64_t BufferedResourceLoader::instance_size() {
322 return instance_size_;
323 }
324
325 bool BufferedResourceLoader::range_supported() {
326 return range_supported_;
327 }
328
329 /////////////////////////////////////////////////////////////////////////////
330 // blink::WebURLLoaderClient implementation.
331 void BufferedResourceLoader::willFollowRedirect(
332 WebURLLoader* loader,
333 WebURLRequest& newRequest,
334 const WebURLResponse& redirectResponse,
335 int64_t encodedDataLength) {
336 // The load may have been stopped and |start_cb| is destroyed.
337 // In this case we shouldn't do anything.
338 if (start_cb_.is_null()) {
339 // Set the url in the request to an invalid value (empty url).
340 newRequest.setURL(blink::WebURL());
341 return;
342 }
343
344 // Only allow |single_origin_| if we haven't seen a different origin yet.
345 if (single_origin_)
346 single_origin_ = url_.GetOrigin() == GURL(newRequest.url()).GetOrigin();
347
348 url_ = newRequest.url();
349 }
350
351 void BufferedResourceLoader::didSendData(
352 WebURLLoader* loader,
353 unsigned long long bytes_sent,
354 unsigned long long total_bytes_to_be_sent) {
355 NOTIMPLEMENTED();
356 }
357
358 void BufferedResourceLoader::didReceiveResponse(
359 WebURLLoader* loader,
360 const WebURLResponse& response) {
361 DVLOG(1) << "didReceiveResponse: HTTP/"
362 << (response.httpVersion() == WebURLResponse::HTTPVersion_0_9
363 ? "0.9"
364 : response.httpVersion() == WebURLResponse::HTTPVersion_1_0
365 ? "1.0"
366 : response.httpVersion() ==
367 WebURLResponse::HTTPVersion_1_1
368 ? "1.1"
369 : response.httpVersion() ==
370 WebURLResponse::HTTPVersion_2_0
371 ? "2.0"
372 : "Unknown")
373 << " " << response.httpStatusCode();
374 DCHECK(active_loader_.get());
375 response_original_url_ = response.wasFetchedViaServiceWorker()
376 ? response.originalURLViaServiceWorker()
377 : response.url();
378
379 // The loader may have been stopped and |start_cb| is destroyed.
380 // In this case we shouldn't do anything.
381 if (start_cb_.is_null())
382 return;
383
384 uint32_t reasons = GetReasonsForUncacheability(response);
385 might_be_reused_from_cache_in_future_ = reasons == 0;
386 UMA_HISTOGRAM_BOOLEAN("Media.CacheUseful", reasons == 0);
387 int shift = 0;
388 int max_enum = base::bits::Log2Ceiling(kMaxReason);
389 while (reasons) {
390 DCHECK_LT(shift, max_enum); // Sanity check.
391 if (reasons & 0x1) {
392 UMA_HISTOGRAM_ENUMERATION("Media.UncacheableReason",
393 shift,
394 max_enum); // PRESUBMIT_IGNORE_UMA_MAX
395 }
396
397 reasons >>= 1;
398 ++shift;
399 }
400
401 // Expected content length can be |kPositionNotSpecified|, in that case
402 // |content_length_| is not specified and this is a streaming response.
403 content_length_ = response.expectedContentLength();
404
405 // We make a strong assumption that when we reach here we have either
406 // received a response from HTTP/HTTPS protocol or the request was
407 // successful (in particular range request). So we only verify the partial
408 // response for HTTP and HTTPS protocol.
409 if (url_.SchemeIsHTTPOrHTTPS()) {
410 bool partial_response = (response.httpStatusCode() == kHttpPartialContent);
411 bool ok_response = (response.httpStatusCode() == kHttpOK);
412
413 if (IsRangeRequest()) {
414 // Check to see whether the server supports byte ranges.
415 std::string accept_ranges =
416 response.httpHeaderField("Accept-Ranges").utf8();
417 range_supported_ = (accept_ranges.find("bytes") != std::string::npos);
418
419 // If we have verified the partial response and it is correct, we will
420 // return kOk. It's also possible for a server to support range requests
421 // without advertising "Accept-Ranges: bytes".
422 if (partial_response && VerifyPartialResponse(response)) {
423 range_supported_ = true;
424 } else if (ok_response && first_byte_position_ == 0 &&
425 last_byte_position_ == kPositionNotSpecified) {
426 // We accept a 200 response for a Range:0- request, trusting the
427 // Accept-Ranges header, because Apache thinks that's a reasonable thing
428 // to return.
429 instance_size_ = content_length_;
430 } else {
431 MEDIA_LOG(ERROR, media_log_)
432 << "Failed loading buffered resource using range request due to "
433 "invalid server response. HTTP status code="
434 << response.httpStatusCode();
435 DoneStart(kFailed);
436 return;
437 }
438 } else {
439 instance_size_ = content_length_;
440 if (response.httpStatusCode() != kHttpOK) {
441 // We didn't request a range but server didn't reply with "200 OK".
442 MEDIA_LOG(ERROR, media_log_)
443 << "Failed loading buffered resource due to invalid server "
444 "response. HTTP status code=" << response.httpStatusCode();
445 DoneStart(kFailed);
446 return;
447 }
448 }
449
450 } else {
451 CHECK_EQ(instance_size_, kPositionNotSpecified);
452 if (content_length_ != kPositionNotSpecified) {
453 if (first_byte_position_ == kPositionNotSpecified)
454 instance_size_ = content_length_;
455 else if (last_byte_position_ == kPositionNotSpecified)
456 instance_size_ = content_length_ + first_byte_position_;
457 }
458 }
459
460 // Calls with a successful response.
461 DoneStart(kOk);
462 }
463
464 void BufferedResourceLoader::didReceiveData(WebURLLoader* loader,
465 const char* data,
466 int data_length,
467 int encoded_data_length,
468 int encoded_body_length) {
469 DVLOG(1) << "didReceiveData: " << data_length << " bytes";
470 DCHECK(active_loader_.get());
471 DCHECK_GT(data_length, 0);
472
473 buffer_.Append(reinterpret_cast<const uint8_t*>(data), data_length);
474
475 // If there is an active read request, try to fulfill the request.
476 if (HasPendingRead() && CanFulfillRead())
477 ReadInternal();
478
479 // At last see if the buffer is full and we need to defer the downloading.
480 UpdateDeferBehavior();
481
482 // Consume excess bytes from our in-memory buffer if necessary.
483 if (buffer_.forward_bytes() > buffer_.forward_capacity()) {
484 int excess = buffer_.forward_bytes() - buffer_.forward_capacity();
485 bool success = buffer_.Seek(excess);
486 DCHECK(success);
487 offset_ += first_offset_ + excess;
488 }
489
490 // Notify latest progress and buffered offset.
491 progress_cb_.Run(offset_ + buffer_.forward_bytes() - 1);
492 Log();
493 }
494
495 void BufferedResourceLoader::didDownloadData(
496 blink::WebURLLoader* loader,
497 int dataLength,
498 int encoded_data_length) {
499 NOTIMPLEMENTED();
500 }
501
502 void BufferedResourceLoader::didReceiveCachedMetadata(
503 WebURLLoader* loader,
504 const char* data,
505 int data_length) {
506 NOTIMPLEMENTED();
507 }
508
509 void BufferedResourceLoader::didFinishLoading(
510 WebURLLoader* loader,
511 double finishTime,
512 int64_t total_encoded_data_length) {
513 DVLOG(1) << "didFinishLoading";
514 DCHECK(active_loader_.get());
515
516 // We're done with the loader.
517 active_loader_.reset();
518 loading_cb_.Run(kLoadingFinished);
519
520 // If we didn't know the |instance_size_| we do now.
521 if (instance_size_ == kPositionNotSpecified) {
522 instance_size_ = offset_ + buffer_.forward_bytes();
523 }
524
525 // If there is a start callback, run it.
526 if (!start_cb_.is_null()) {
527 DCHECK(read_cb_.is_null())
528 << "Shouldn't have a read callback during start";
529 DoneStart(kOk);
530 return;
531 }
532
533 // Don't leave read callbacks hanging around.
534 if (HasPendingRead()) {
535 // Try to fulfill with what is in the buffer.
536 if (CanFulfillRead())
537 ReadInternal();
538 else
539 DoneRead(kCacheMiss, 0);
540 }
541 }
542
543 void BufferedResourceLoader::didFail(
544 WebURLLoader* loader,
545 const WebURLError& error) {
546 DVLOG(1) << "didFail: reason=" << error.reason
547 << ", isCancellation=" << error.isCancellation
548 << ", domain=" << error.domain.utf8().data()
549 << ", localizedDescription="
550 << error.localizedDescription.utf8().data();
551 DCHECK(active_loader_.get());
552 MEDIA_LOG(ERROR, media_log_)
553 << "Failed loading buffered resource. Error code=" << error.reason;
554
555 // We don't need to continue loading after failure.
556 //
557 // Keep it alive until we exit this method so that |error| remains valid.
558 std::unique_ptr<ActiveLoader> active_loader = std::move(active_loader_);
559 loader_failed_ = true;
560 loading_cb_.Run(kLoadingFailed);
561
562 // Don't leave start callbacks hanging around.
563 if (!start_cb_.is_null()) {
564 DCHECK(read_cb_.is_null())
565 << "Shouldn't have a read callback during start";
566 DoneStart(kFailed);
567 return;
568 }
569
570 // Don't leave read callbacks hanging around.
571 if (HasPendingRead()) {
572 DoneRead(kFailed, 0);
573 }
574 }
575
576 bool BufferedResourceLoader::HasSingleOrigin() const {
577 DCHECK(start_cb_.is_null())
578 << "Start() must complete before calling HasSingleOrigin()";
579 return single_origin_;
580 }
581
582 bool BufferedResourceLoader::DidPassCORSAccessCheck() const {
583 // Until Start() is done we don't know, assume no until we know.
584 if (!start_cb_.is_null())
585 return false;
586 return !loader_failed_ && cors_mode_ != kUnspecified;
587 }
588
589 void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) {
590 if (!might_be_reused_from_cache_in_future_ && strategy == kNeverDefer)
591 strategy = kCapacityDefer;
592 defer_strategy_ = strategy;
593 UpdateDeferBehavior();
594 }
595
596 void BufferedResourceLoader::SetPlaybackRate(double playback_rate) {
597 playback_rate_ = playback_rate;
598
599 // This is a pause so don't bother updating the buffer window as we'll likely
600 // get unpaused in the future.
601 if (playback_rate_ == 0.0)
602 return;
603
604 // Abort any cancellations in progress if playback starts.
605 if (playback_rate_ > 0 && cancel_upon_deferral_)
606 cancel_upon_deferral_ = false;
607
608 UpdateBufferWindow();
609 }
610
611 void BufferedResourceLoader::SetBitrate(int bitrate) {
612 DCHECK(bitrate >= 0);
613 bitrate_ = bitrate;
614 UpdateBufferWindow();
615 }
616
617 /////////////////////////////////////////////////////////////////////////////
618 // Helper methods.
619
620 void BufferedResourceLoader::UpdateBufferWindow() {
621 int backward_capacity;
622 int forward_capacity;
623 ComputeTargetBufferWindow(
624 playback_rate_, bitrate_, &backward_capacity, &forward_capacity);
625
626 // This does not evict data from the buffer if the new capacities are less
627 // than the current capacities; the new limits will be enforced after the
628 // existing excess buffered data is consumed.
629 buffer_.set_backward_capacity(backward_capacity);
630 buffer_.set_forward_capacity(forward_capacity);
631 }
632
633 void BufferedResourceLoader::UpdateDeferBehavior() {
634 if (!active_loader_)
635 return;
636
637 SetDeferred(ShouldDefer());
638 }
639
640 void BufferedResourceLoader::SetDeferred(bool deferred) {
641 if (active_loader_->deferred() == deferred)
642 return;
643
644 active_loader_->SetDeferred(deferred);
645 loading_cb_.Run(deferred ? kLoadingDeferred : kLoading);
646
647 if (deferred && cancel_upon_deferral_)
648 CancelUponDeferral();
649 }
650
651 bool BufferedResourceLoader::ShouldDefer() const {
652 switch(defer_strategy_) {
653 case kNeverDefer:
654 return false;
655
656 case kReadThenDefer:
657 DCHECK(read_cb_.is_null() || last_offset_ > buffer_.forward_bytes())
658 << "We shouldn't stop deferring if we can fulfill the read";
659 return read_cb_.is_null();
660
661 case kCapacityDefer:
662 return buffer_.forward_bytes() >= buffer_.forward_capacity();
663 }
664 NOTREACHED();
665 return false;
666 }
667
668 bool BufferedResourceLoader::CanFulfillRead() const {
669 // If we are reading too far in the backward direction.
670 if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
671 return false;
672
673 // If the start offset is too far ahead.
674 if (first_offset_ >= buffer_.forward_bytes())
675 return false;
676
677 // At the point, we verified that first byte requested is within the buffer.
678 // If the request has completed, then just returns with what we have now.
679 if (!active_loader_)
680 return true;
681
682 // If the resource request is still active, make sure the whole requested
683 // range is covered.
684 if (last_offset_ > buffer_.forward_bytes())
685 return false;
686
687 return true;
688 }
689
690 bool BufferedResourceLoader::WillFulfillRead() const {
691 // Trying to read too far behind.
692 if (first_offset_ < 0 && (first_offset_ + buffer_.backward_bytes()) < 0)
693 return false;
694
695 // Trying to read too far ahead.
696 if ((first_offset_ - buffer_.forward_bytes()) >= kForwardWaitThreshold)
697 return false;
698
699 // The resource request has completed, there's no way we can fulfill the
700 // read request.
701 if (!active_loader_)
702 return false;
703
704 return true;
705 }
706
707 void BufferedResourceLoader::ReadInternal() {
708 // Seek to the first byte requested.
709 bool ret = buffer_.Seek(first_offset_);
710 DCHECK(ret);
711
712 // Then do the read.
713 int read = buffer_.Read(read_buffer_, read_size_);
714 offset_ += first_offset_ + read;
715
716 // And report with what we have read.
717 DoneRead(kOk, read);
718 }
719
720 int64_t BufferedResourceLoader::first_byte_position() const {
721 return first_byte_position_;
722 }
723
724 // static
725 bool BufferedResourceLoader::ParseContentRange(
726 const std::string& content_range_str,
727 int64_t* first_byte_position,
728 int64_t* last_byte_position,
729 int64_t* instance_size) {
730 const std::string kUpThroughBytesUnit = "bytes ";
731 if (!base::StartsWith(content_range_str, kUpThroughBytesUnit,
732 base::CompareCase::SENSITIVE)) {
733 return false;
734 }
735 std::string range_spec =
736 content_range_str.substr(kUpThroughBytesUnit.length());
737 size_t dash_offset = range_spec.find("-");
738 size_t slash_offset = range_spec.find("/");
739
740 if (dash_offset == std::string::npos || slash_offset == std::string::npos ||
741 slash_offset < dash_offset || slash_offset + 1 == range_spec.length()) {
742 return false;
743 }
744 if (!base::StringToInt64(range_spec.substr(0, dash_offset),
745 first_byte_position) ||
746 !base::StringToInt64(range_spec.substr(dash_offset + 1,
747 slash_offset - dash_offset - 1),
748 last_byte_position)) {
749 return false;
750 }
751 if (slash_offset == range_spec.length() - 2 &&
752 range_spec[slash_offset + 1] == '*') {
753 *instance_size = kPositionNotSpecified;
754 } else {
755 if (!base::StringToInt64(range_spec.substr(slash_offset + 1),
756 instance_size)) {
757 return false;
758 }
759 }
760 if (*last_byte_position < *first_byte_position ||
761 (*instance_size != kPositionNotSpecified &&
762 *last_byte_position >= *instance_size)) {
763 return false;
764 }
765
766 return true;
767 }
768
769 void BufferedResourceLoader::CancelUponDeferral() {
770 cancel_upon_deferral_ = true;
771 if (active_loader_ && active_loader_->deferred())
772 active_loader_.reset();
773 }
774
775 int64_t BufferedResourceLoader::GetMemoryUsage() const {
776 return buffer_.forward_bytes() + buffer_.backward_bytes();
777 }
778
779 bool BufferedResourceLoader::VerifyPartialResponse(
780 const WebURLResponse& response) {
781 int64_t first_byte_position, last_byte_position, instance_size;
782 if (!ParseContentRange(response.httpHeaderField("Content-Range").utf8(),
783 &first_byte_position, &last_byte_position,
784 &instance_size)) {
785 return false;
786 }
787
788 if (instance_size != kPositionNotSpecified) {
789 instance_size_ = instance_size;
790 }
791
792 if (first_byte_position_ != kPositionNotSpecified &&
793 first_byte_position_ != first_byte_position) {
794 return false;
795 }
796
797 // TODO(hclam): I should also check |last_byte_position|, but since
798 // we will never make such a request that it is ok to leave it unimplemented.
799 return true;
800 }
801
802 void BufferedResourceLoader::DoneRead(Status status, int bytes_read) {
803 if (saved_forward_capacity_) {
804 buffer_.set_forward_capacity(saved_forward_capacity_);
805 saved_forward_capacity_ = 0;
806 }
807 read_position_ = 0;
808 read_size_ = 0;
809 read_buffer_ = NULL;
810 first_offset_ = 0;
811 last_offset_ = 0;
812 Log();
813
814 base::ResetAndReturn(&read_cb_).Run(status, bytes_read);
815 }
816
817
818 void BufferedResourceLoader::DoneStart(Status status) {
819 base::ResetAndReturn(&start_cb_).Run(status);
820 }
821
822 bool BufferedResourceLoader::IsRangeRequest() const {
823 return first_byte_position_ != kPositionNotSpecified;
824 }
825
826 void BufferedResourceLoader::Log() {
827 media_log_->AddEvent(
828 media_log_->CreateBufferedExtentsChangedEvent(
829 offset_ - buffer_.backward_bytes(),
830 offset_,
831 offset_ + buffer_.forward_bytes()));
832 }
833
834 } // namespace media
OLDNEW
« no previous file with comments | « media/blink/buffered_resource_loader.h ('k') | media/blink/buffered_resource_loader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698