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

Side by Side Diff: content/renderer/media/buffered_resource_loader.cc

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

Powered by Google App Engine
This is Rietveld 408576698