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 |