Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "media/blink/buffered_data_source_host_impl.h" | 5 #include "media/blink/buffered_data_source_host_impl.h" |
| 6 | 6 |
| 7 #include "media/base/timestamp_constants.h" | 7 #include "media/base/timestamp_constants.h" |
| 8 | 8 |
| 9 namespace media { | 9 namespace media { |
| 10 | 10 |
| 11 BufferedDataSourceHostImpl::BufferedDataSourceHostImpl() | 11 const double kDownloadHistoryWindowSeconds = 10.0; |
| 12 const size_t kDownloadHistoryMaxEntries = 1024; | |
| 13 | |
| 14 BufferedDataSourceHostImpl::BufferedDataSourceHostImpl( | |
| 15 const base::Closure& progress_cb) | |
| 12 : total_bytes_(0), | 16 : total_bytes_(0), |
| 13 did_loading_progress_(false) { } | 17 did_loading_progress_(false), |
| 18 progress_cb_(progress_cb) {} | |
| 14 | 19 |
| 15 BufferedDataSourceHostImpl::~BufferedDataSourceHostImpl() { } | 20 BufferedDataSourceHostImpl::~BufferedDataSourceHostImpl() { } |
| 16 | 21 |
| 17 void BufferedDataSourceHostImpl::SetTotalBytes(int64_t total_bytes) { | 22 void BufferedDataSourceHostImpl::SetTotalBytes(int64_t total_bytes) { |
| 18 total_bytes_ = total_bytes; | 23 total_bytes_ = total_bytes; |
| 19 } | 24 } |
| 20 | 25 |
| 26 int64_t BufferedDataSourceHostImpl::UnloadedBytesInInterval( | |
| 27 const Interval<int64_t>& interval) const { | |
| 28 int64_t bytes = 0; | |
| 29 auto i = buffered_byte_ranges_.find(interval.begin); | |
| 30 while (i != buffered_byte_ranges_.end()) { | |
| 31 if (i.interval_begin() >= interval.end) | |
| 32 break; | |
| 33 if (!i.value()) { | |
| 34 Interval<int64_t> intersection = i.interval().Intersect(interval); | |
| 35 if (!intersection.Empty()) { | |
| 36 bytes += intersection.end - intersection.begin; | |
| 37 } | |
| 38 } | |
| 39 ++i; | |
| 40 } | |
| 41 return bytes; | |
| 42 } | |
| 43 | |
| 21 void BufferedDataSourceHostImpl::AddBufferedByteRange(int64_t start, | 44 void BufferedDataSourceHostImpl::AddBufferedByteRange(int64_t start, |
| 22 int64_t end) { | 45 int64_t end) { |
| 23 const auto i = buffered_byte_ranges_.find(start); | 46 int64_t new_bytes = UnloadedBytesInInterval(Interval<int64_t>(start, end)); |
| 24 if (i.value() && i.interval_end() >= end) { | 47 if (new_bytes == 0) { |
| 25 // No change | 48 // No change |
| 26 return; | 49 return; |
| 27 } | 50 } |
| 28 buffered_byte_ranges_.SetInterval(start, end, 1); | 51 buffered_byte_ranges_.SetInterval(start, end, 1); |
| 29 did_loading_progress_ = true; | 52 did_loading_progress_ = true; |
| 53 | |
| 54 base::TimeTicks now = base::TimeTicks::Now(); | |
| 55 int64_t bytes_so_far = 0; | |
| 56 if (!download_history_.empty()) | |
| 57 bytes_so_far = download_history_.back().second; | |
| 58 bytes_so_far += new_bytes; | |
| 59 if (download_history_.size() >= kDownloadHistoryMaxEntries) { | |
| 60 download_history_.back() = std::make_pair(now, bytes_so_far); | |
|
chcunningham
2017/04/06 16:55:41
why not always push_back? iiuc this is overwriting
hubbe
2017/04/06 21:25:38
We don't loose any data, we just loose precision i
| |
| 61 } else { | |
| 62 download_history_.push_back(std::make_pair(now, bytes_so_far)); | |
| 63 } | |
| 64 while (download_history_.back().first - download_history_.front().first > | |
| 65 base::TimeDelta::FromSecondsD(kDownloadHistoryWindowSeconds) || | |
| 66 download_history_.size() >= kDownloadHistoryMaxEntries) { | |
| 67 download_history_.pop_front(); | |
| 68 } | |
| 69 if (!progress_cb_.is_null()) { | |
| 70 progress_cb_.Run(); | |
| 71 } | |
| 30 } | 72 } |
| 31 | 73 |
| 32 static base::TimeDelta TimeForByteOffset(int64_t byte_offset, | 74 static base::TimeDelta TimeForByteOffset(int64_t byte_offset, |
| 33 int64_t total_bytes, | 75 int64_t total_bytes, |
| 34 base::TimeDelta duration) { | 76 base::TimeDelta duration) { |
| 35 double position = static_cast<double>(byte_offset) / total_bytes; | 77 double position = static_cast<double>(byte_offset) / total_bytes; |
| 36 // Snap to the beginning/end where the approximation can look especially bad. | 78 // Snap to the beginning/end where the approximation can look especially bad. |
| 37 if (position < 0.01) | 79 if (position < 0.01) |
| 38 return base::TimeDelta(); | 80 return base::TimeDelta(); |
| 39 if (position > 0.99) | 81 if (position > 0.99) |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 59 } | 101 } |
| 60 } | 102 } |
| 61 } | 103 } |
| 62 | 104 |
| 63 bool BufferedDataSourceHostImpl::DidLoadingProgress() { | 105 bool BufferedDataSourceHostImpl::DidLoadingProgress() { |
| 64 bool ret = did_loading_progress_; | 106 bool ret = did_loading_progress_; |
| 65 did_loading_progress_ = false; | 107 did_loading_progress_ = false; |
| 66 return ret; | 108 return ret; |
| 67 } | 109 } |
| 68 | 110 |
| 111 double BufferedDataSourceHostImpl::DownloadRate() const { | |
| 112 if (download_history_.size() < 5) | |
| 113 return 0.0; | |
| 114 | |
| 115 // The data we get is bursty, so we get multiple measuring points very close | |
| 116 // together. These bursts will often lead us to over-estimate the download | |
| 117 // rate. By iterating over the beginning of the time series and picking the | |
| 118 // data point that has the lowest download rate, we avoid over-estimating. | |
| 119 double download_rate = 1.0E20; | |
|
mlamouri (slow - plz ping)
2017/04/06 11:32:56
Why 1e20 and not a negative value instead?
hubbe
2017/04/06 21:25:38
Because I use std::min() below.
mlamouri (slow - plz ping)
2017/04/07 11:23:44
Missed that. Can you use INT_MAX? `std::numeric_li
| |
| 120 for (int i = 0; i < std::min<int>(20, download_history_.size() - 3); i++) { | |
|
chcunningham
2017/04/06 16:55:41
I don't follow the min(20, ...). If you only want
hubbe
2017/04/06 21:25:38
Each entry contains the cumulative downloaded byte
| |
| 121 int64_t downloaded_bytes = | |
| 122 download_history_.back().second - download_history_[i].second; | |
| 123 double downloaded_seconds = | |
| 124 (download_history_.back().first - download_history_[i].first) | |
| 125 .InSecondsF(); | |
| 126 if (downloaded_seconds <= 0.0) | |
| 127 continue; | |
| 128 download_rate = | |
| 129 std::min(download_rate, downloaded_bytes / downloaded_seconds); | |
| 130 } | |
| 131 if (download_rate == 1.0E20) | |
| 132 return 0.0; | |
| 133 return download_rate; | |
| 134 } | |
| 135 | |
| 136 bool BufferedDataSourceHostImpl::CanPlayThrough( | |
| 137 base::TimeDelta current_position, | |
| 138 base::TimeDelta media_duration, | |
| 139 double playback_rate) const { | |
| 140 if (!total_bytes_ || media_duration <= base::TimeDelta()) | |
| 141 return false; | |
| 142 if (current_position > media_duration) | |
| 143 return true; | |
| 144 double fraction = current_position.InSecondsF() / media_duration.InSecondsF(); | |
| 145 int64_t byte_pos = total_bytes_ * fraction; | |
| 146 if (byte_pos < 0) | |
| 147 byte_pos = 0; | |
| 148 | |
| 149 double download_rate = DownloadRate(); | |
| 150 if (download_rate == 0.0) | |
| 151 return false; | |
| 152 | |
| 153 int64_t unloaded_bytes = | |
| 154 UnloadedBytesInInterval(Interval<int64_t>(byte_pos, total_bytes_)); | |
| 155 return unloaded_bytes / download_rate < | |
| 156 (media_duration - current_position).InSecondsF() / playback_rate; | |
| 157 } | |
| 158 | |
| 69 } // namespace media | 159 } // namespace media |
| OLD | NEW |