Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/media/buffered_data_source.h" | 5 #include "webkit/media/buffered_data_source.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "media/base/media_log.h" | 9 #include "media/base/media_log.h" |
| 10 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
| 11 | 11 |
| 12 using WebKit::WebFrame; | 12 using WebKit::WebFrame; |
| 13 | 13 |
| 14 namespace webkit_media { | 14 namespace webkit_media { |
| 15 | 15 |
| 16 // BufferedDataSource has an intermediate buffer, this value governs the initial | 16 // BufferedDataSource has an intermediate buffer, this value governs the initial |
| 17 // size of that buffer. It is set to 32KB because this is a typical read size | 17 // size of that buffer. It is set to 32KB because this is a typical read size |
| 18 // of FFmpeg. | 18 // of FFmpeg. |
| 19 static const int kInitialReadBufferSize = 32768; | 19 static const int kInitialReadBufferSize = 32768; |
| 20 | 20 |
| 21 // Number of cache misses we allow for a single Read() before signalling an | 21 // Number of cache misses we allow for a single Read() before signalling an |
| 22 // error. | 22 // error. |
| 23 static const int kNumCacheMissRetries = 3; | 23 static const int kNumCacheMissRetries = 3; |
| 24 | 24 |
| 25 // Non-HTTP resources are assumed to be fully loaded so we ignore any | |
| 26 // loading/progress related callbacks. | |
|
scherkus (not reviewing)
2012/07/06 16:28:35
see http://codereview.chromium.org/10692106/ -- I
Ami GONE FROM CHROMIUM
2012/07/09 03:25:10
FTR, you mean https://chromiumcodereview.appspot.c
| |
| 27 static void NonHttpLoadingCallback(BufferedResourceLoader::LoadingState) {} | |
| 28 static void NonHttpProgressCallback(int64) {} | |
| 29 | |
| 25 BufferedDataSource::BufferedDataSource( | 30 BufferedDataSource::BufferedDataSource( |
| 26 MessageLoop* render_loop, | 31 MessageLoop* render_loop, |
| 27 WebFrame* frame, | 32 WebFrame* frame, |
| 28 media::MediaLog* media_log) | 33 media::MediaLog* media_log) |
| 29 : total_bytes_(kPositionNotSpecified), | 34 : total_bytes_(kPositionNotSpecified), |
| 30 buffered_bytes_(0), | 35 buffered_bytes_(0), |
| 31 streaming_(false), | 36 streaming_(false), |
| 32 frame_(frame), | 37 frame_(frame), |
| 33 loader_(NULL), | 38 loader_(NULL), |
| 34 is_downloading_data_(false), | 39 is_downloading_data_(false), |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 url_ = url; | 93 url_ = url; |
| 89 | 94 |
| 90 initialize_cb_ = initialize_cb; | 95 initialize_cb_ = initialize_cb; |
| 91 | 96 |
| 92 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { | 97 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { |
| 93 // Do an unbounded range request starting at the beginning. If the server | 98 // Do an unbounded range request starting at the beginning. If the server |
| 94 // responds with 200 instead of 206 we'll fall back into a streaming mode. | 99 // responds with 200 instead of 206 we'll fall back into a streaming mode. |
| 95 loader_.reset(CreateResourceLoader(0, kPositionNotSpecified)); | 100 loader_.reset(CreateResourceLoader(0, kPositionNotSpecified)); |
| 96 loader_->Start( | 101 loader_->Start( |
| 97 base::Bind(&BufferedDataSource::HttpInitialStartCallback, this), | 102 base::Bind(&BufferedDataSource::HttpInitialStartCallback, this), |
| 98 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 103 base::Bind(&BufferedDataSource::HttpLoadingCallback, this), |
| 104 base::Bind(&BufferedDataSource::HttpProgressCallback, this), | |
| 99 frame_); | 105 frame_); |
| 100 return; | 106 return; |
| 101 } | 107 } |
| 102 | 108 |
| 103 // For all other protocols, assume they support range request. We fetch | 109 // For all other protocols, assume they support range request. We fetch |
| 104 // the full range of the resource to obtain the instance size because | 110 // the full range of the resource to obtain the instance size because |
| 105 // we won't be served HTTP headers. | 111 // we won't be served HTTP headers. |
| 106 loader_.reset(CreateResourceLoader(kPositionNotSpecified, | 112 loader_.reset(CreateResourceLoader(kPositionNotSpecified, |
| 107 kPositionNotSpecified)); | 113 kPositionNotSpecified)); |
| 108 loader_->Start( | 114 loader_->Start( |
| 109 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), | 115 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), |
| 110 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 116 base::Bind(&NonHttpLoadingCallback), |
| 117 base::Bind(&NonHttpProgressCallback), | |
| 111 frame_); | 118 frame_); |
| 112 } | 119 } |
| 113 | 120 |
| 114 void BufferedDataSource::SetPreload(Preload preload) { | 121 void BufferedDataSource::SetPreload(Preload preload) { |
| 115 DCHECK(MessageLoop::current() == render_loop_); | 122 DCHECK(MessageLoop::current() == render_loop_); |
| 116 preload_ = preload; | 123 preload_ = preload; |
| 117 } | 124 } |
| 118 | 125 |
| 119 bool BufferedDataSource::HasSingleOrigin() { | 126 bool BufferedDataSource::HasSingleOrigin() { |
| 120 DCHECK(MessageLoop::current() == render_loop_); | 127 DCHECK(MessageLoop::current() == render_loop_); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 248 if (stopped_on_render_loop_) | 255 if (stopped_on_render_loop_) |
| 249 return; | 256 return; |
| 250 | 257 |
| 251 { | 258 { |
| 252 // If there's no outstanding read then return early. | 259 // If there's no outstanding read then return early. |
| 253 base::AutoLock auto_lock(lock_); | 260 base::AutoLock auto_lock(lock_); |
| 254 if (read_cb_.is_null()) | 261 if (read_cb_.is_null()) |
| 255 return; | 262 return; |
| 256 } | 263 } |
| 257 | 264 |
| 265 // Start reading from where we last left off until the end of the resource. | |
| 258 loader_.reset( | 266 loader_.reset( |
| 259 CreateResourceLoader(last_read_start_, kPositionNotSpecified)); | 267 CreateResourceLoader(last_read_start_, kPositionNotSpecified)); |
| 260 loader_->Start( | 268 if (url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)) { |
| 261 base::Bind(&BufferedDataSource::PartialReadStartCallback, this), | 269 loader_->Start( |
| 262 base::Bind(&BufferedDataSource::NetworkEventCallback, this), | 270 base::Bind(&BufferedDataSource::PartialReadStartCallback, this), |
| 263 frame_); | 271 base::Bind(&BufferedDataSource::HttpLoadingCallback, this), |
| 272 base::Bind(&BufferedDataSource::HttpProgressCallback, this), | |
| 273 frame_); | |
| 274 } else { | |
| 275 loader_->Start( | |
| 276 base::Bind(&BufferedDataSource::NonHttpInitialStartCallback, this), | |
| 277 base::Bind(&NonHttpLoadingCallback), | |
| 278 base::Bind(&NonHttpProgressCallback), | |
| 279 frame_); | |
| 280 } | |
| 264 } | 281 } |
| 265 | 282 |
| 266 void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { | 283 void BufferedDataSource::SetPlaybackRateTask(float playback_rate) { |
| 267 DCHECK(MessageLoop::current() == render_loop_); | 284 DCHECK(MessageLoop::current() == render_loop_); |
| 268 DCHECK(loader_.get()); | 285 DCHECK(loader_.get()); |
| 269 | 286 |
| 270 if (playback_rate != 0) | 287 if (playback_rate != 0) |
| 271 media_has_played_ = true; | 288 media_has_played_ = true; |
| 272 | 289 |
| 273 playback_rate_ = playback_rate; | 290 playback_rate_ = playback_rate; |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 497 cache_miss_retries_left_--; | 514 cache_miss_retries_left_--; |
| 498 render_loop_->PostTask(FROM_HERE, | 515 render_loop_->PostTask(FROM_HERE, |
| 499 base::Bind(&BufferedDataSource::RestartLoadingTask, this)); | 516 base::Bind(&BufferedDataSource::RestartLoadingTask, this)); |
| 500 return; | 517 return; |
| 501 } | 518 } |
| 502 | 519 |
| 503 // Fall through to signal a read error. | 520 // Fall through to signal a read error. |
| 504 bytes_read = kReadError; | 521 bytes_read = kReadError; |
| 505 } | 522 } |
| 506 | 523 |
| 507 // We need to prevent calling to filter host and running the callback if | 524 // TODO(scherkus): we shouldn't have to lock to signal host(), see |
| 508 // we have received the stop signal. We need to lock down the whole callback | 525 // http://crbug.com/113712 for details. |
| 509 // method to prevent bad things from happening. The reason behind this is | |
| 510 // that we cannot guarantee tasks on render thread have completely stopped | |
| 511 // when we receive the Stop() method call. So only way to solve this is to | |
| 512 // let tasks on render thread to run but make sure they don't call outside | |
| 513 // this object when Stop() method is ever called. Locking this method is safe | |
| 514 // because |lock_| is only acquired in tasks on render thread. | |
| 515 base::AutoLock auto_lock(lock_); | 526 base::AutoLock auto_lock(lock_); |
| 516 if (stop_signal_received_) | 527 if (stop_signal_received_) |
| 517 return; | 528 return; |
| 518 | 529 |
| 519 if (bytes_read > 0) { | 530 if (bytes_read > 0) { |
| 520 memcpy(read_buffer_, intermediate_read_buffer_.get(), bytes_read); | 531 memcpy(read_buffer_, intermediate_read_buffer_.get(), bytes_read); |
| 521 } else if (bytes_read == 0 && total_bytes_ == kPositionNotSpecified) { | 532 } else if (bytes_read == 0 && total_bytes_ == kPositionNotSpecified) { |
| 522 // We've reached the end of the file and we didn't know the total size | 533 // We've reached the end of the file and we didn't know the total size |
| 523 // before. Update the total size so Read()s past the end of the file will | 534 // before. Update the total size so Read()s past the end of the file will |
| 524 // fail like they would if we had known the file size at the beginning. | 535 // fail like they would if we had known the file size at the beginning. |
| 525 total_bytes_ = loader_->instance_size(); | 536 total_bytes_ = loader_->instance_size(); |
| 526 | 537 |
| 527 if (host() && total_bytes_ != kPositionNotSpecified) { | 538 if (host() && total_bytes_ != kPositionNotSpecified) { |
| 528 host()->SetTotalBytes(total_bytes_); | 539 host()->SetTotalBytes(total_bytes_); |
| 529 host()->AddBufferedByteRange(last_read_start_, total_bytes_); | 540 host()->AddBufferedByteRange(last_read_start_, total_bytes_); |
| 530 } | 541 } |
| 531 } | 542 } |
| 532 DoneRead_Locked(bytes_read); | 543 DoneRead_Locked(bytes_read); |
| 533 } | 544 } |
| 534 | 545 |
| 535 void BufferedDataSource::NetworkEventCallback() { | 546 void BufferedDataSource::HttpLoadingCallback( |
| 547 BufferedResourceLoader::LoadingState state) { | |
| 536 DCHECK(MessageLoop::current() == render_loop_); | 548 DCHECK(MessageLoop::current() == render_loop_); |
| 537 DCHECK(loader_.get()); | 549 DCHECK(url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)); |
| 538 | 550 |
| 539 // In case of non-HTTP request we don't need to report network events, | 551 // TODO(scherkus): we shouldn't have to lock to signal host(), see |
| 540 // so return immediately. | 552 // http://crbug.com/113712 for details. |
| 541 if (!url_.SchemeIs(kHttpScheme) && !url_.SchemeIs(kHttpsScheme)) | |
| 542 return; | |
| 543 | |
| 544 bool is_downloading_data = loader_->is_downloading_data(); | |
| 545 int64 current_buffered_position = loader_->GetBufferedPosition(); | |
| 546 | |
| 547 // If we get an unspecified value, return immediately. | |
| 548 if (current_buffered_position == kPositionNotSpecified) | |
| 549 return; | |
| 550 | |
| 551 // We need to prevent calling to filter host and running the callback if | |
| 552 // we have received the stop signal. We need to lock down the whole callback | |
| 553 // method to prevent bad things from happening. The reason behind this is | |
| 554 // that we cannot guarantee tasks on render thread have completely stopped | |
| 555 // when we receive the Stop() method call. So only way to solve this is to | |
| 556 // let tasks on render thread to run but make sure they don't call outside | |
| 557 // this object when Stop() method is ever called. Locking this method is safe | |
| 558 // because |lock_| is only acquired in tasks on render thread. | |
| 559 base::AutoLock auto_lock(lock_); | 553 base::AutoLock auto_lock(lock_); |
| 560 if (stop_signal_received_) | 554 if (stop_signal_received_) |
| 561 return; | 555 return; |
| 562 | 556 |
| 557 bool is_downloading_data; | |
| 558 switch (state) { | |
| 559 case BufferedResourceLoader::kLoading: | |
| 560 is_downloading_data = true; | |
| 561 break; | |
| 562 case BufferedResourceLoader::kLoadingDeferred: | |
| 563 is_downloading_data = false; | |
| 564 break; | |
| 565 | |
| 566 // TODO(scherkus): we don't signal network activity changes when loads | |
| 567 // complete or fail to preserve existing behaviour when deferring is | |
| 568 // toggled, however SetNetworkActivity() should use a similar enum as there | |
| 569 // isn't any signal today to notify the client that loading has | |
| 570 // failed/finished (we only get errors on subsequent reads). | |
| 571 case BufferedResourceLoader::kLoadingFailed: | |
| 572 case BufferedResourceLoader::kLoadingFinished: | |
| 573 return; | |
| 574 } | |
| 575 | |
| 563 if (is_downloading_data != is_downloading_data_) { | 576 if (is_downloading_data != is_downloading_data_) { |
| 564 is_downloading_data_ = is_downloading_data; | 577 is_downloading_data_ = is_downloading_data; |
| 565 if (host()) | 578 if (host()) |
| 566 host()->SetNetworkActivity(is_downloading_data); | 579 host()->SetNetworkActivity(is_downloading_data); |
| 567 } | 580 } |
| 581 } | |
| 568 | 582 |
| 569 if (host() && current_buffered_position > last_read_start_) | 583 void BufferedDataSource::HttpProgressCallback(int64 position) { |
| 570 host()->AddBufferedByteRange(last_read_start_, current_buffered_position); | 584 DCHECK(MessageLoop::current() == render_loop_); |
| 585 DCHECK(url_.SchemeIs(kHttpScheme) || url_.SchemeIs(kHttpsScheme)); | |
| 586 | |
| 587 // TODO(scherkus): we shouldn't have to lock to signal host(), see | |
| 588 // http://crbug.com/113712 for details. | |
| 589 base::AutoLock auto_lock(lock_); | |
| 590 if (stop_signal_received_) | |
| 591 return; | |
| 592 | |
| 593 if (host() && position > last_read_start_) | |
| 594 host()->AddBufferedByteRange(last_read_start_, position); | |
| 571 } | 595 } |
| 572 | 596 |
| 573 void BufferedDataSource::UpdateHostState_Locked() { | 597 void BufferedDataSource::UpdateHostState_Locked() { |
| 574 // Called from various threads, under lock. | |
| 575 lock_.AssertAcquired(); | 598 lock_.AssertAcquired(); |
| 576 | 599 |
| 577 if (!host()) | 600 if (!host()) |
| 578 return; | 601 return; |
| 579 | 602 |
| 580 if (total_bytes_ != kPositionNotSpecified) | 603 if (total_bytes_ != kPositionNotSpecified) |
| 581 host()->SetTotalBytes(total_bytes_); | 604 host()->SetTotalBytes(total_bytes_); |
| 582 if (buffered_bytes_ > last_read_start_) | 605 if (buffered_bytes_ > last_read_start_) |
| 583 host()->AddBufferedByteRange(last_read_start_, buffered_bytes_); | 606 host()->AddBufferedByteRange(last_read_start_, buffered_bytes_); |
| 584 } | 607 } |
| 585 | 608 |
| 586 } // namespace webkit_media | 609 } // namespace webkit_media |
| OLD | NEW |