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

Unified Diff: media/blink/buffered_data_source_host_impl.cc

Issue 2796193002: fix canplaythrough (Closed)
Patch Set: kSpecCompliantCanPlayThrough Created 3 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: media/blink/buffered_data_source_host_impl.cc
diff --git a/media/blink/buffered_data_source_host_impl.cc b/media/blink/buffered_data_source_host_impl.cc
index 30542adcf37416f2006fd8acb6dbf5eac57d4833..1b4f8723f7ad841c155840f5c651fed603c43159 100644
--- a/media/blink/buffered_data_source_host_impl.cc
+++ b/media/blink/buffered_data_source_host_impl.cc
@@ -8,9 +8,28 @@
namespace media {
-BufferedDataSourceHostImpl::BufferedDataSourceHostImpl()
+// We want a relatively small window for estimating bandwidth,
+// that way we don't need to worry too much about seeks and pause
+// throwing off the estimates.
+constexpr base::TimeDelta kDownloadHistoryWindowSeconds =
+ base::TimeDelta::FromSecondsD(10.0);
+
+// Limit the number of entries in the rate estimator queue.
+// 1024 entries should be more than enough.
+constexpr size_t kDownloadHistoryMaxEntries = 1024;
+
+// Just in case someone gives progress one byte at a time,
+// let's aggregate progress updates together until we reach
+// at least this many bytes.
+constexpr int64_t kDownloadHistoryMinBytesPerEntry = 1000;
+
+BufferedDataSourceHostImpl::BufferedDataSourceHostImpl(
+ base::RepeatingClosure progress_cb,
+ base::TickClock* tick_clock)
: total_bytes_(0),
- did_loading_progress_(false) { }
+ did_loading_progress_(false),
+ progress_cb_(std::move(progress_cb)),
+ tick_clock_(tick_clock) {}
BufferedDataSourceHostImpl::~BufferedDataSourceHostImpl() { }
@@ -18,15 +37,56 @@ void BufferedDataSourceHostImpl::SetTotalBytes(int64_t total_bytes) {
total_bytes_ = total_bytes;
}
+int64_t BufferedDataSourceHostImpl::UnloadedBytesInInterval(
+ const Interval<int64_t>& interval) const {
+ int64_t bytes = 0;
+ auto i = buffered_byte_ranges_.find(interval.begin);
+ while (i != buffered_byte_ranges_.end()) {
+ if (i.interval_begin() >= interval.end)
+ break;
+ if (!i.value()) {
+ Interval<int64_t> intersection = i.interval().Intersect(interval);
+ if (!intersection.Empty())
+ bytes += intersection.end - intersection.begin;
+ }
+ ++i;
+ }
+ return bytes;
+}
+
void BufferedDataSourceHostImpl::AddBufferedByteRange(int64_t start,
int64_t end) {
- const auto i = buffered_byte_ranges_.find(start);
- if (i.value() && i.interval_end() >= end) {
+ int64_t new_bytes = UnloadedBytesInInterval(Interval<int64_t>(start, end));
+ if (new_bytes == 0) {
// No change
return;
}
buffered_byte_ranges_.SetInterval(start, end, 1);
did_loading_progress_ = true;
+
+ base::TimeTicks now = tick_clock_->NowTicks();
+ int64_t bytes_so_far = 0;
+ if (!download_history_.empty())
+ bytes_so_far = download_history_.back().second;
+ bytes_so_far += new_bytes;
+
+ // If the difference between the last entry and the second to last entry is
+ // less than kDownloadHistoryMinBytesPerEntry, just overwrite the last entry.
+ if (download_history_.size() > 1 &&
+ download_history_.back().second - (download_history_.end() - 2)->second <
+ kDownloadHistoryMinBytesPerEntry) {
+ download_history_.back() = std::make_pair(now, bytes_so_far);
+ } else {
+ download_history_.emplace_back(now, bytes_so_far);
+ }
+ DCHECK_GE(download_history_.size(), 1u);
+ // Drop entries that are too old.
+ while (download_history_.size() > kDownloadHistoryMaxEntries ||
+ download_history_.back().first - download_history_.front().first >
+ kDownloadHistoryWindowSeconds) {
+ download_history_.pop_front();
+ }
+ progress_cb_.Run();
}
static base::TimeDelta TimeForByteOffset(int64_t byte_offset,
@@ -66,4 +126,65 @@ bool BufferedDataSourceHostImpl::DidLoadingProgress() {
return ret;
}
+double BufferedDataSourceHostImpl::DownloadRate() const {
+ // If the download history is really small, any estimate we make is going to
+ // be wildly inaccurate, so let's not make any estimates until we have more
+ // data.
+ if (download_history_.size() < 5)
+ return 0.0;
+
+ // The data we get is bursty, so we get multiple measuring points very close
+ // together. These bursts will often lead us to over-estimate the download
+ // rate. By iterating over the beginning of the time series and picking the
+ // data point that has the lowest download rate, we avoid over-estimating.
+ const double kVeryLargeRate = 1.0E20;
+ double download_rate = kVeryLargeRate;
+ for (int i = 0; i < std::min<int>(20, download_history_.size() - 3); i++) {
+ int64_t downloaded_bytes =
+ download_history_.back().second - download_history_[i].second;
+ base::TimeTicks now = tick_clock_->NowTicks();
+ base::TimeDelta downloaded_seconds = now - download_history_[i].first;
+ if (downloaded_seconds <= base::TimeDelta())
+ continue;
+ download_rate = std::min(
+ download_rate, downloaded_bytes / downloaded_seconds.InSecondsF());
+ }
+ return download_rate == kVeryLargeRate ? 0.0 : download_rate;
+}
+
+bool BufferedDataSourceHostImpl::CanPlayThrough(
+ base::TimeDelta current_position,
+ base::TimeDelta media_duration,
+ double playback_rate) const {
+ DCHECK_GE(playback_rate, 0);
+ if (!total_bytes_ || media_duration <= base::TimeDelta() ||
+ media_duration == kInfiniteDuration) {
+ return false;
+ }
+ if (current_position > media_duration)
+ return true;
+ double fraction = current_position.InSecondsF() / media_duration.InSecondsF();
+ int64_t byte_pos = total_bytes_ * fraction;
+ if (byte_pos < 0)
+ byte_pos = 0;
+
+ int64_t unloaded_bytes =
+ UnloadedBytesInInterval(Interval<int64_t>(byte_pos, total_bytes_));
+
+ if (unloaded_bytes == 0)
+ return true;
+
+ double download_rate = DownloadRate();
+ if (download_rate <= 0.0)
+ return false;
+
+ return unloaded_bytes / download_rate <
+ (media_duration - current_position).InSecondsF() / playback_rate;
+}
+
+void BufferedDataSourceHostImpl::SetTickClockForTest(
+ base::TickClock* tick_clock) {
+ tick_clock_ = tick_clock;
+}
+
} // namespace media
« no previous file with comments | « media/blink/buffered_data_source_host_impl.h ('k') | media/blink/buffered_data_source_host_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698