Index: webkit/glue/media/buffered_resource_loader.cc |
=================================================================== |
--- webkit/glue/media/buffered_resource_loader.cc (revision 105891) |
+++ webkit/glue/media/buffered_resource_loader.cc (working copy) |
@@ -35,31 +35,76 @@ |
// Define the number of bytes in a megabyte. |
static const size_t kMegabyte = 1024 * 1024; |
-// Backward capacity of the buffer, by default 2MB. |
-static const size_t kBackwardCapacity = 2 * kMegabyte; |
+// Minimum capacity of the buffer in forward or backward direction. |
+// |
+// 2MB is an arbitrary limit; it just seems to be "good enough" in practice. |
+static const size_t kMinBufferCapacity = 2 * kMegabyte; |
-// Forward capacity of the buffer, by default 10MB. |
-static const size_t kForwardCapacity = 10 * kMegabyte; |
+// Maximum capacity of the buffer in forward or backward direction. This is |
+// effectively the largest single read the code path can handle. |
+// 20MB is an arbitrary limit; it just seems to be "good enough" in practice. |
+static const size_t kMaxBufferCapacity = 20 * kMegabyte; |
-// Maximum forward capacity of the buffer, by default 20MB. This is effectively |
-// the largest single read teh code path can handle. 20MB is an arbitrary limit; |
-// it just seems to be "good enough" in practice. |
-static const size_t kMaxForwardCapacity = 20 * kMegabyte; |
- |
// Maximum number of bytes outside the buffer we will wait for in order to |
// fulfill a read. If a read starts more than 2MB away from the data we |
// currently have in the buffer, we will not wait for buffer to reach the read's |
// location and will instead reset the request. |
static const int kForwardWaitThreshold = 2 * kMegabyte; |
+// Computes the suggested backward and forward capacity for the buffer |
+// if one wants to play at |playback_rate| * the natural playback speed. |
+// Use a value of 0 for |bitrate| if it is unknown. |
+static void ComputeTargetBufferWindow(float playback_rate, int bitrate, |
+ size_t* out_backward_capacity, |
+ size_t* out_forward_capacity) { |
+ static const size_t kDefaultBitrate = 200 * 1024 * 8; // 200 Kbps. |
+ static const size_t kMaxBitrate = 20 * kMegabyte * 8; // 20 Mbps. |
+ static const float kMaxPlaybackRate = 25.0; |
+ static const size_t kTargetSecondsBufferedAhead = 10; |
+ static const size_t kTargetSecondsBufferedBehind = 2; |
+ |
+ // Use a default bit rate if unknown and clamp to prevent overflow. |
+ if (bitrate <= 0) |
+ bitrate = kDefaultBitrate; |
+ bitrate = std::min(static_cast<size_t>(bitrate), kMaxBitrate); |
+ |
+ // Only scale the buffer window for playback rates greater than 1.0 in |
+ // magnitude and clamp to prevent overflow. |
+ bool backward_playback = false; |
+ if (playback_rate < 0.0f) { |
+ backward_playback = true; |
+ playback_rate *= -1.0f; |
+ } |
+ |
+ playback_rate = std::max(playback_rate, 1.0f); |
+ playback_rate = std::min(playback_rate, kMaxPlaybackRate); |
+ |
+ size_t bytes_per_second = static_cast<size_t>(playback_rate * bitrate / 8.0); |
+ |
+ // Clamp between kMinBufferCapacity and kMaxBufferCapacity. |
+ *out_forward_capacity = std::max( |
+ kTargetSecondsBufferedAhead * bytes_per_second, kMinBufferCapacity); |
+ *out_backward_capacity = std::max( |
+ kTargetSecondsBufferedBehind * bytes_per_second, kMinBufferCapacity); |
+ |
+ *out_forward_capacity = std::min(*out_forward_capacity, kMaxBufferCapacity); |
+ *out_backward_capacity = std::min(*out_backward_capacity, kMaxBufferCapacity); |
+ |
+ if (backward_playback) |
+ std::swap(*out_forward_capacity, *out_backward_capacity); |
+} |
+ |
+ |
BufferedResourceLoader::BufferedResourceLoader( |
const GURL& url, |
int64 first_byte_position, |
int64 last_byte_position, |
+ DeferStrategy strategy, |
+ int bitrate, |
+ float playback_rate, |
media::MediaLog* media_log) |
- : buffer_(new media::SeekableBuffer(kBackwardCapacity, kForwardCapacity)), |
- deferred_(false), |
- defer_strategy_(kReadThenDefer), |
+ : deferred_(false), |
+ defer_strategy_(strategy), |
completed_(false), |
range_requested_(false), |
range_supported_(false), |
@@ -79,7 +124,15 @@ |
first_offset_(0), |
last_offset_(0), |
keep_test_loader_(false), |
+ bitrate_(bitrate), |
+ playback_rate_(playback_rate), |
media_log_(media_log) { |
+ |
+ size_t backward_capacity; |
+ size_t forward_capacity; |
+ ComputeTargetBufferWindow( |
+ playback_rate_, bitrate_, &backward_capacity, &forward_capacity); |
+ buffer_.reset(new media::SeekableBuffer(backward_capacity, forward_capacity)); |
} |
BufferedResourceLoader::~BufferedResourceLoader() { |
@@ -200,7 +253,7 @@ |
// Make sure |read_size_| is not too large for the buffer to ever be able to |
// fulfill the read request. |
- if (read_size_ > kMaxForwardCapacity) { |
+ if (read_size_ > kMaxBufferCapacity) { |
DoneRead(net::ERR_FAILED); |
return; |
} |
@@ -230,7 +283,7 @@ |
saved_forward_capacity_ = buffer_->forward_capacity(); |
buffer_->set_forward_capacity(read_size_); |
} |
- return; |
+ return; |
} |
// Make a callback to report failure. |
@@ -489,8 +542,47 @@ |
return single_origin_; |
} |
+void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) { |
+ defer_strategy_ = strategy; |
+ UpdateDeferBehavior(); |
+} |
+ |
+void BufferedResourceLoader::SetPlaybackRate(float playback_rate) { |
+ playback_rate_ = playback_rate; |
+ |
+ // This is a pause so don't bother updating the buffer window as we'll likely |
+ // get unpaused in the future. |
+ if (playback_rate_ == 0.0) |
+ return; |
+ |
+ UpdateBufferWindow(); |
+} |
+ |
+void BufferedResourceLoader::SetBitrate(int bitrate) { |
+ DCHECK(bitrate >= 0); |
+ bitrate_ = bitrate; |
+ UpdateBufferWindow(); |
+} |
+ |
///////////////////////////////////////////////////////////////////////////// |
// Helper methods. |
+ |
+void BufferedResourceLoader::UpdateBufferWindow() { |
+ if (!buffer_.get()) |
+ return; |
+ |
+ size_t backward_capacity; |
+ size_t forward_capacity; |
+ ComputeTargetBufferWindow( |
+ playback_rate_, bitrate_, &backward_capacity, &forward_capacity); |
+ |
+ // This does not evict data from the buffer if the new capacities are less |
+ // than the current capacities; the new limits will be enforced after the |
+ // existing excess buffered data is consumed. |
+ buffer_->set_backward_capacity(backward_capacity); |
+ buffer_->set_forward_capacity(forward_capacity); |
+} |
+ |
void BufferedResourceLoader::UpdateDeferBehavior() { |
if (!url_loader_.get() || !buffer_.get()) |
return; |
@@ -503,11 +595,6 @@ |
} |
} |
-void BufferedResourceLoader::UpdateDeferStrategy(DeferStrategy strategy) { |
- defer_strategy_ = strategy; |
- UpdateDeferBehavior(); |
-} |
- |
bool BufferedResourceLoader::ShouldEnableDefer() { |
// If we're already deferring, then enabling makes no sense. |
if (deferred_) |