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

Side by Side Diff: media/filters/source_buffer_stream.cc

Issue 10389185: Implement start, end, and middle overlaps for SourceBufferStream (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase ToT Created 8 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "media/filters/source_buffer_stream.h" 5 #include "media/filters/source_buffer_stream.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 11
12 namespace media { 12 namespace media {
13 13
14 // Helper class representing a range of buffered data. All buffers in a 14 // Helper class representing a range of buffered data. All buffers in a
15 // SourceBufferRange are ordered sequentially in presentation order with no 15 // SourceBufferRange are ordered sequentially in presentation order with no
16 // gaps. 16 // gaps.
17 class SourceBufferRange { 17 class SourceBufferRange {
18 public: 18 public:
19 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; 19 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
20 20
21 SourceBufferRange(); 21 // Creates a source buffer range with |new_buffers|. |new_buffers| cannot be
22 // empty and the front of |new_buffers| must be a keyframe.
23 SourceBufferRange(const BufferQueue& new_buffers);
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 add explicit
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Good catch, done.
22 24
23 // Adds |new_buffers| into this range. |new_buffers| must belong to this 25 // Appends |buffers| to the end of the range and updates |keyframe_map_| as
24 // range. Garbage collection may occur after Append(). 26 // it encounters new keyframes. Assumes |buffers| belongs at the end of the
25 void Append(const BufferQueue& new_buffers); 27 // range.
28 void AppendToEnd(const BufferQueue& buffers);
29 bool CanAppendToEnd(const BufferQueue& buffers) const;
30
31 // Appends the buffers from |range| into this range.
32 // The first buffer in |range| must come directly after the last buffer
33 // in this range.
34 // If |transfer_current_position| is true, |range|'s |next_buffer_position_|
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 next_buffer_position_ -> next_buffer_index_?
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Done.
35 // is transfered to this SourceBufferRange.
36 void AppendToEnd(const SourceBufferRange& range,
37 bool transfer_current_position);
38 bool CanAppendToEnd(const SourceBufferRange& range) const;
26 39
27 // Updates |next_buffer_index_| to point to the Buffer containing |timestamp|. 40 // Updates |next_buffer_index_| to point to the Buffer containing |timestamp|.
28 // Assumes |timestamp| is valid and in this range. 41 // Assumes |timestamp| is valid and in this range.
29 void Seek(base::TimeDelta timestamp); 42 void Seek(base::TimeDelta timestamp);
30 43
31 // Updates |next_buffer_index_| to point to next keyframe after or equal to 44 // Updates |next_buffer_index_| to point to next keyframe after or equal to
32 // |timestamp|. If there is no such keyframe, then this range will seek to 45 // |timestamp|.
33 // the end and return kNoTimestamp(). 46 void SeekAfter(base::TimeDelta timestamp);
34 // Assumes |timestamp| is valid and in this range. 47
35 base::TimeDelta SeekAfter(base::TimeDelta timestamp); 48 // Finds the next keyframe from |buffers_| after |timestamp|, and creates and
49 // returns a new SourceBufferRange with the buffers from that keyframe onward.
50 // The buffers in the new SourceBufferRange are moved out of this range. If
51 // there is no keyframe after |timestamp|, SplitRange() returns null and this
52 // range is unmodified.
53 SourceBufferRange* SplitRange(base::TimeDelta timestamp);
54
55 // Deletes the buffers from this range whose timestamps are greater than or
56 // equal to |buffer|'s timestamp.
57 // Resets |next_buffer_index_| if the buffer after |next_buffer_index_| was
58 // deleted.
59 // If |deleted_buffers| or |next_buffer| are null, they are ignored.
60 // Otherwise, |deleted_buffers| contains the buffers that were deleted from
61 // this range, and |next_buffer| points to the deleted next buffer or to
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 nit: Perhaps reword "deleted next buffer" to somet
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Did some rewording, and also deleted the other com
62 // |deleted_buffers.end()| if the next buffer was not deleted.
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 nit: "the next buffer was not deleted" -> "|next_b
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Done.
63 void DeleteAfter(scoped_refptr<StreamParserBuffer> buffer,
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 nit: It might be good to mention that keyframe_map
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Done.
64 BufferQueue* deleted_buffers,
65 BufferQueue::iterator* next_buffer);
66
67 // Deletes all buffers in range.
68 // If |deleted_buffers| or |next_buffer| are null, they are ignored.
69 // Otherwise, |deleted_buffers| contains the buffers that were deleted from
70 // this range, and |next_buffer| points to the deleted next buffer or to
71 // |deleted_buffers.end()| if the next buffer was not deleted.
72 void DeleteAll(BufferQueue* deleted_buffers,
73 BufferQueue::iterator* next_buffer);
36 74
37 // Updates |out_buffer| with the next buffer in presentation order. Seek() 75 // Updates |out_buffer| with the next buffer in presentation order. Seek()
38 // must be called before calls to GetNextBuffer(), and buffers are returned 76 // must be called before calls to GetNextBuffer(), and buffers are returned
39 // in order from the last call to Seek(). Returns true if |out_buffer| is 77 // in order from the last call to Seek(). Returns true if |out_buffer| is
40 // filled with a valid buffer, false if there is not enough data to fulfill 78 // filled with a valid buffer, false if there is not enough data to fulfill
41 // the request. 79 // the request.
42 bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer); 80 bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer);
81
82 // Returns the timestamp of the next buffer that will be returned from
83 // GetNextBuffer(). Returns kNoTimestamp() if Seek() has never been called or
84 // if this range does not have the next buffer yet.
43 base::TimeDelta GetNextTimestamp() const; 85 base::TimeDelta GetNextTimestamp() const;
44 86
87 // Returns the end timestamp of the buffered data. (Note that this is equal to
88 // the last buffer's timestamp + its duration.) Returns kNoTimestamp if the
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 nit: Can we have an empty range? If not remove tha
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 It is possible (e.g. after completely overlapping
89 // range is empty.
90 base::TimeDelta GetEndTimestamp() const;
91
45 // Returns the Timespan of buffered time in this range. 92 // Returns the Timespan of buffered time in this range.
46 SourceBufferStream::Timespan GetBufferedTime() const; 93 SourceBufferStream::Timespan GetBufferedTime() const;
47 94
48 // Appends the buffers from |range| into this range.
49 // The first buffer in |range| must come directly after the last buffer
50 // in this range.
51 // If |transfer_current_position| is true, |range|'s |next_buffer_position_|
52 // is transfered to this SourceBufferRange.
53 void AppendToEnd(const SourceBufferRange& range,
54 bool transfer_current_position);
55 bool CanAppendToEnd(const SourceBufferRange& range) const;
56 bool CanAppendToEnd(const BufferQueue& buffers) const;
57
58 // Returns whether a buffer with a starting timestamp of |timestamp| would 95 // Returns whether a buffer with a starting timestamp of |timestamp| would
59 // belong in this range. This includes a buffer that would be appended to 96 // belong in this range. This includes a buffer that would be appended to
60 // the end of the range. 97 // the end of the range.
61 // Returns 0 if |timestamp| is in this range, -1 if |timestamp| appears 98 // Returns 0 if |timestamp| is in this range, -1 if |timestamp| appears
62 // before this range, or 1 if |timestamp| appears after this range. 99 // before this range, or 1 if |timestamp| appears after this range.
63 int BelongsToRange(base::TimeDelta timestamp) const; 100 int BelongsToRange(base::TimeDelta timestamp) const;
64 101
65 // Returns true if the range has enough data to seek to the specified 102 // Returns true if the range has enough data to seek to the specified
66 // |timestamp|, false otherwise. 103 // |timestamp|, false otherwise.
67 bool CanSeekTo(base::TimeDelta timestamp) const; 104 bool CanSeekTo(base::TimeDelta timestamp) const;
68 105
69 // Returns true if this range's buffered timespan completely overlaps the 106 // Returns true if this range's buffered timespan completely overlaps the
70 // buffered timespan of |range|. 107 // buffered timespan of |range|.
71 bool CompletelyOverlaps(const SourceBufferRange& range) const; 108 bool CompletelyOverlaps(const SourceBufferRange& range) const;
72 109
73 // Returns true if the end of this range contains buffers that overlaps with 110 // Returns true if the end of this range contains buffers that overlaps with
74 // the beginning of |range|. 111 // the beginning of |range|.
75 bool EndOverlaps(const SourceBufferRange& range) const; 112 bool EndOverlaps(const SourceBufferRange& range) const;
76 113
77 // Functions that tell how |buffers| intersects with this range.
78 // TODO(vrk): These functions should be unnecessary when overlapping the
79 // selected range is implemented properly. (crbug.com/126560)
80 bool IsStartOverlappedBy(const BufferQueue& buffers) const;
81 bool IsEndOverlappedBy(const BufferQueue& buffers) const;
82 bool IsCompletelyOverlappedBy(const BufferQueue& buffers) const;
83
84 private: 114 private:
85 // Appends |buffers| to the end of the range and updates |keyframe_map_| as 115 // Helper method to delete buffers in |buffers_| starting from
86 // it encounters new keyframes. Assumes |buffers| belongs at the end of the 116 // |starting_point|, an iterator in |buffers_|.
87 // range. 117 // If |deleted_buffers| or |next_buffer| are null, they are ignored.
88 void AppendToEnd(const BufferQueue& buffers); 118 // Otherwise, |deleted_buffers| contains the buffers that were deleted from
119 // this range, and |next_buffer| points to the deleted next buffer or to
120 // |deleted_buffers.end()| if the next buffer was not deleted.
121 void DeleteAfter(BufferQueue::iterator starting_point,
122 BufferQueue* deleted_buffers,
123 BufferQueue::iterator* next_buffer);
89 124
90 // Returns the start timestamp of the range, or kNoTimestamp if the range is 125 // Returns the start timestamp of the range, or kNoTimestamp if the range is
91 // empty. 126 // empty.
92 base::TimeDelta BufferedStart() const; 127 base::TimeDelta BufferedStart() const;
93 128
94 // Returns the end timestamp of the buffered data. (Note that this is equal to 129 // Returns the end timestamp of the buffered data. (Note that this is equal to
95 // the last buffer's timestamp + its duration.) Returns kNoTimestamp if the 130 // the last buffer's timestamp + its duration.) Returns kNoTimestamp if the
96 // range is empty. 131 // range is empty.
97 base::TimeDelta BufferedEnd() const; 132 base::TimeDelta BufferedEnd() const;
98 133
99 // An ordered list of buffers in this range. 134 // An ordered list of buffers in this range.
100 BufferQueue buffers_; 135 BufferQueue buffers_;
101 136
102 // Maps keyframe timestamps to its index position in |buffers_|. 137 // Maps keyframe timestamps to its index position in |buffers_|.
103 typedef std::map<base::TimeDelta, size_t> KeyframeMap; 138 typedef std::map<base::TimeDelta, size_t> KeyframeMap;
104 KeyframeMap keyframe_map_; 139 KeyframeMap keyframe_map_;
105 140
106 // Index into |buffers_| for the next buffer to be returned by 141 // Index into |buffers_| for the next buffer to be returned by
107 // GetBufferedTime(), set to -1 before Seek(). 142 // GetBufferedTime(), set to -1 before Seek().
108 int next_buffer_index_; 143 int next_buffer_index_;
109 144
145 // True if the range needs to wait for the next keyframe to be appended before
146 // returning buffers from GetNextBuffer().
147 bool waiting_for_keyframe_;
148
149 // If |waiting_for_keyframe_| is true, this range will wait for the next
150 // keyframe with timestamp >= |next_keyframe_timestamp_|.
151 base::TimeDelta next_keyframe_timestamp_;
152
110 DISALLOW_COPY_AND_ASSIGN(SourceBufferRange); 153 DISALLOW_COPY_AND_ASSIGN(SourceBufferRange);
111 }; 154 };
112 155
113 } // namespace media 156 } // namespace media
114 157
115 // Helper method that returns true if |ranges| is sorted in increasing order, 158 // Helper method that returns true if |ranges| is sorted in increasing order,
116 // false otherwise. 159 // false otherwise.
117 static bool IsRangeListSorted( 160 static bool IsRangeListSorted(
118 const std::list<media::SourceBufferRange*>& ranges) { 161 const std::list<media::SourceBufferRange*>& ranges) {
119 base::TimeDelta prev = media::kNoTimestamp(); 162 base::TimeDelta prev = media::kNoTimestamp();
120 for (std::list<media::SourceBufferRange*>::const_iterator itr = 163 for (std::list<media::SourceBufferRange*>::const_iterator itr =
121 ranges.begin(); itr != ranges.end(); itr++) { 164 ranges.begin(); itr != ranges.end(); itr++) {
122 media::SourceBufferStream::Timespan buffered = (*itr)->GetBufferedTime(); 165 media::SourceBufferStream::Timespan buffered = (*itr)->GetBufferedTime();
123 if (prev != media::kNoTimestamp() && prev >= buffered.first) 166 if (prev != media::kNoTimestamp() && prev >= buffered.first)
124 return false; 167 return false;
125 prev = buffered.second; 168 prev = buffered.second;
126 } 169 }
127 return true; 170 return true;
128 } 171 }
129 172
130 // Comparison function for two Buffers based on timestamp. 173 // Comparison function for two Buffers based on timestamp.
131 static bool BufferComparator(scoped_refptr<media::Buffer> first, 174 static bool BufferComparator(
132 scoped_refptr<media::Buffer> second) { 175 const scoped_refptr<media::StreamParserBuffer>& first,
176 const scoped_refptr<media::StreamParserBuffer>& second) {
133 return first->GetTimestamp() < second->GetTimestamp(); 177 return first->GetTimestamp() < second->GetTimestamp();
134 } 178 }
135 179
136 // Returns the upper bound for the starting timestamp for the next buffer 180 // Returns the upper bound for the starting timestamp for the next buffer
137 // in sequence after |buffer|. Assumes |buffer|'s timestamp and 181 // in sequence after |buffer|. Assumes |buffer|'s timestamp and
138 // duration are valid. 182 // duration are valid.
139 static base::TimeDelta MaxNextTimestamp( 183 static base::TimeDelta MaxNextTimestamp(
140 const scoped_refptr<media::StreamParserBuffer>& buffer) { 184 const scoped_refptr<media::StreamParserBuffer>& buffer) {
141 // Because we do not know exactly when is the next timestamp, any buffer 185 // Because we do not know exactly when is the next timestamp, any buffer
142 // that starts within 1/3 of the duration past the end of this buffer 186 // that starts within 1/3 of the duration past the end of this buffer
143 // is considered the next buffer in the sequence. 187 // is considered the next buffer in the sequence.
144 return buffer->GetEndTimestamp() + buffer->GetDuration() / 3; 188 return buffer->GetEndTimestamp() + buffer->GetDuration() / 3;
145 } 189 }
146 190
147 // Returns true if |timestamp| is the timestamp of the next buffer in 191 // Returns true if |timestamp| is the timestamp of the next buffer in
148 // sequence after |buffer|, false otherwise. 192 // sequence after |buffer|, false otherwise.
149 static bool IsNextInSequence( 193 static bool IsNextInSequence(
150 const scoped_refptr<media::StreamParserBuffer>& buffer, 194 const scoped_refptr<media::StreamParserBuffer>& buffer,
151 base::TimeDelta timestamp) { 195 base::TimeDelta timestamp) {
152 return timestamp >= buffer->GetEndTimestamp() && 196 return timestamp >= buffer->GetEndTimestamp() &&
153 timestamp <= MaxNextTimestamp(buffer); 197 timestamp <= MaxNextTimestamp(buffer);
154 } 198 }
155 199
156 namespace media { 200 namespace media {
157 201
158 SourceBufferStream::SourceBufferStream() 202 SourceBufferStream::SourceBufferStream()
159 : seek_pending_(false), 203 : seek_pending_(false),
160 seek_buffer_timestamp_(kNoTimestamp()), 204 seek_buffer_timestamp_(kNoTimestamp()),
161 selected_range_(NULL), 205 selected_range_(NULL) {
162 waiting_for_keyframe_(false) {
163 } 206 }
164 207
165 SourceBufferStream::~SourceBufferStream() { 208 SourceBufferStream::~SourceBufferStream() {
166 while (!ranges_.empty()) { 209 while (!ranges_.empty()) {
167 delete ranges_.front(); 210 delete ranges_.front();
168 ranges_.pop_front(); 211 ranges_.pop_front();
169 } 212 }
170 } 213 }
171 214
172 bool SourceBufferStream::Append( 215 bool SourceBufferStream::Append(
173 const SourceBufferStream::BufferQueue& buffers) { 216 const SourceBufferStream::BufferQueue& buffers) {
174 DCHECK(!buffers.empty()); 217 DCHECK(!buffers.empty());
175 218
176 // Check to see if |buffers| will overlap the currently |selected_range_|, 219 RangeList::iterator range_for_new_buffers = ranges_.end();
177 // and if so, ignore this Append() request.
178 // TODO(vrk): Support overlapping selected range properly. (crbug.com/126560)
179 if (selected_range_ &&
180 (selected_range_->IsEndOverlappedBy(buffers) ||
181 selected_range_->IsStartOverlappedBy(buffers))) {
182 return false;
183 }
184
185 SourceBufferRange* range = NULL;
186 RangeList::iterator itr = ranges_.end(); 220 RangeList::iterator itr = ranges_.end();
187 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp(); 221 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp();
188 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) { 222 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) {
189 int range_value = (*itr)->BelongsToRange(start_timestamp); 223 int range_value = (*itr)->BelongsToRange(start_timestamp);
190 224 if (range_value < 0)
191 // |start_timestamp| is before the current range in this loop. Because
192 // |ranges_| is sorted, this means that we need to create a new range and it
193 // should be placed before |itr|.
194 // TODO(vrk): We also break out of the loop if |buffers| completely overlaps
195 // the current range. This is to cover the case when |buffers| belongs to
196 // the current range, but also completely overlaps it. This should be
197 // removed when start overlap is handled properly.
198 if (range_value < 0 || (*itr)->IsCompletelyOverlappedBy(buffers))
199 break; 225 break;
200 226
201 if (range_value == 0) { 227 if (range_value == 0) {
202 // Found an existing range into which we can append buffers. 228 // Found an existing range into which we can append buffers.
203 range = *itr; 229 range_for_new_buffers = itr;
204
205 if (range->CanAppendToEnd(buffers) && waiting_for_keyframe_) {
206 // Currently we do not support the case where the next buffer after the
207 // buffers in the track buffer is not a keyframe.
208 if (!buffers.front()->IsKeyframe())
209 return false;
210 waiting_for_keyframe_ = false;
211 }
212 break; 230 break;
213 } 231 }
214 } 232 }
215 233
216 if (!range) { 234 if (range_for_new_buffers == ranges_.end()) {
217 // Ranges must begin with a keyframe. 235 // Ranges must begin with a keyframe.
218 if (!buffers.front()->IsKeyframe()) 236 if (!buffers.front()->IsKeyframe())
219 return false; 237 return false;
220 238 range_for_new_buffers =
221 range = new SourceBufferRange(); 239 ranges_.insert(itr, new SourceBufferRange(buffers));
222 itr = ranges_.insert(itr, range); 240 } else {
241 InsertIntoExistingRange(range_for_new_buffers, buffers);
223 } 242 }
224 243
225 // Append buffers to the appropriate range.
226 range->Append(buffers);
227
228 // Increment |itr| to be the range after |range|.
229 itr++;
230
231 // Resolve overlaps. 244 // Resolve overlaps.
232 itr = ResolveCompleteOverlaps(itr, range); 245 ResolveCompleteOverlaps(range_for_new_buffers);
233 itr = ResolveEndOverlaps(itr, range); 246 ResolveEndOverlap(range_for_new_buffers);
234 MergeWithAdjacentRangeIfNecessary(itr, range); 247 MergeWithAdjacentRangeIfNecessary(range_for_new_buffers);
235 248
236 // Finally, try to complete pending seek if one exists. 249 // Finally, try to complete pending seek if one exists.
237 if (seek_pending_) 250 if (seek_pending_)
238 Seek(seek_buffer_timestamp_); 251 Seek(seek_buffer_timestamp_);
239 252
240 DCHECK(IsRangeListSorted(ranges_)); 253 DCHECK(IsRangeListSorted(ranges_));
241 return true; 254 return true;
242 } 255 }
243 256
244 SourceBufferStream::RangeList::iterator 257 void SourceBufferStream::InsertIntoExistingRange(
245 SourceBufferStream::ResolveCompleteOverlaps( 258 const RangeList::iterator& range_for_new_buffers_itr,
246 const RangeList::iterator& range_itr, SourceBufferRange* new_range) { 259 const BufferQueue& new_buffers) {
247 RangeList::iterator itr = range_itr; 260 SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr;
248 while (itr != ranges_.end() && new_range->CompletelyOverlaps(**itr)) { 261 RangeList::iterator next_range_itr = range_for_new_buffers_itr;
249 if (*itr == selected_range_) { 262 next_range_itr++;
250 // Get the timestamp for the next buffer in the sequence.
251 base::TimeDelta next_timestamp = selected_range_->GetNextTimestamp();
252 // Then seek to the next keyframe after (or equal to) |next_timestamp|.
253 // This will allow us to transition from the old buffers to the new
254 // buffers seamlessly.
255 base::TimeDelta next_keyframe_timestamp =
256 new_range->SeekAfter(next_timestamp);
257 263
258 // If there's no keyframe after |next_timestamp|, then set flag to wait 264 // In case this is a middle overlap, save the buffers that come after the end
259 // for the next keyframe in this range to be appended. 265 // of |new_buffers|, and add them into a new range.
260 if (next_keyframe_timestamp == kNoTimestamp()) 266 SourceBufferRange* new_portion =
261 waiting_for_keyframe_ = true; 267 range_for_new_buffers->SplitRange(new_buffers.back()->GetEndTimestamp());
262 268
263 // Add all the old buffers up until |next_keyframe_timestamp| into 269 if (new_portion) {
264 // |track_buffer_|. If there was no keyframe, then we add all buffers into 270 next_range_itr = ranges_.insert(next_range_itr, new_portion);
265 // |track_buffer_|. 271 // If |range_for_new_buffers| was selected and the next buffer was in the
266 scoped_refptr<StreamParserBuffer> next_buffer; 272 // |new_portion| half, update |selected_range_|.
267 while (selected_range_->GetNextBuffer(&next_buffer) && 273 if (selected_range_ == range_for_new_buffers &&
268 (waiting_for_keyframe_ || 274 new_portion->GetNextTimestamp() != kNoTimestamp()) {
269 next_buffer->GetTimestamp() < next_keyframe_timestamp)) { 275 selected_range_ = new_portion;
270 track_buffer_.push_back(next_buffer); 276 }
271 } 277 }
272 278
273 selected_range_ = new_range; 279 BufferQueue deleted_buffers;
274 } 280 BufferQueue::iterator next_buffer;
275 delete *itr; 281 range_for_new_buffers->DeleteAfter(
276 itr = ranges_.erase(itr); 282 new_buffers.front(), &deleted_buffers, &next_buffer);
283 range_for_new_buffers->AppendToEnd(new_buffers);
284
285 if (selected_range_ == range_for_new_buffers &&
286 !deleted_buffers.empty() && next_buffer != deleted_buffers.end()) {
287 UpdateTrackBuffer(range_for_new_buffers_itr, deleted_buffers, next_buffer);
277 } 288 }
278 return itr;
279 } 289 }
280 290
281 SourceBufferStream::RangeList::iterator 291 void SourceBufferStream::ResolveCompleteOverlaps(
282 SourceBufferStream::ResolveEndOverlaps( 292 const RangeList::iterator& range_with_new_buffers_itr) {
283 const RangeList::iterator& range_itr, SourceBufferRange* new_range) { 293 SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
284 RangeList::iterator itr = range_itr; 294 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
285 while (itr != ranges_.end() && new_range->EndOverlaps(**itr)) { 295 next_range_itr++;
286 DCHECK_NE(*itr, selected_range_); 296
287 delete *itr; 297 while (next_range_itr != ranges_.end() &&
288 itr = ranges_.erase(itr); 298 range_with_new_buffers->CompletelyOverlaps(**next_range_itr)) {
299 if (*next_range_itr == selected_range_) {
300 // Delete everything from the selected range that |new_range| overlaps,
301 // and save the next buffers.
302 BufferQueue deleted_buffers;
303 BufferQueue::iterator next_buffer;
304 (*next_range_itr)->DeleteAll(&deleted_buffers, &next_buffer);
305
306 // Update |selected_range_| then update the track buffer.
307 selected_range_ = range_with_new_buffers;
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 This might not be necessary. It looks like UpdateT
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Yes, you're right, removed and added DCHECK_NE(sel
308 UpdateTrackBuffer(range_with_new_buffers_itr,
309 deleted_buffers, next_buffer);
310 }
311 delete *next_range_itr;
312 next_range_itr = ranges_.erase(next_range_itr);
289 } 313 }
290 return itr; 314 }
315
316 void SourceBufferStream::ResolveEndOverlap(
317 const RangeList::iterator& range_with_new_buffers_itr) {
318 SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
319 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
320 next_range_itr++;
321
322 if (next_range_itr == ranges_.end() ||
323 !range_with_new_buffers->EndOverlaps(**next_range_itr)) {
324 return;
325 }
326
327 // Split the overlapped range after |range_with_new_buffers|'s last buffer
328 // overlaps. Now |overlapped_range| contains only the buffers that do not
329 // belong in |ranges_| anymore, and |new_next_range| contains buffers that
330 // go after |range_with_new_buffers| (without overlap).
331 scoped_ptr<SourceBufferRange> overlapped_range(*next_range_itr);
332 SourceBufferRange* new_next_range =
333 overlapped_range->SplitRange(range_with_new_buffers->GetEndTimestamp());
334
335 // Remove |overlapped_range| from the range list, since it now contains only
336 // buffers that are redundant with |range_with_new_buffers|.
337 next_range_itr = ranges_.erase(next_range_itr);
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 I think it would be better to put this above the p
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Good idea, done.
338
339 // If there were non-overlapped buffers, add the new range to |ranges_|.
340 if (new_next_range)
341 ranges_.insert(next_range_itr, new_next_range);
342
343 // If we didn't overlap a selected range, return.
344 if (selected_range_ != overlapped_range.get())
345 return;
346
347 // If the next buffer was in the |new_next_range| half of the overlapped
348 // range, then the |selected_range_| is now |new_next_range|.
349 if (new_next_range &&
350 new_next_range->GetNextTimestamp() != kNoTimestamp()) {
351 selected_range_ = new_next_range;
352 return;
353 }
354
355 // Otherwise, update track buffer with overlapped buffers.
356 BufferQueue deleted_buffers;
357 scoped_refptr<StreamParserBuffer> buffer;
358 while (overlapped_range->GetNextBuffer(&buffer)) {
359 deleted_buffers.push_back(buffer);
360 }
361 BufferQueue::iterator next_buffer = deleted_buffers.begin();
362 UpdateTrackBuffer(range_with_new_buffers_itr, deleted_buffers, next_buffer);
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 You might want to add a comment here indicating th
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Added a DCHECK and comment.
363 }
364
365 void SourceBufferStream::UpdateTrackBuffer(
366 const RangeList::iterator& range_with_new_buffers_itr,
367 const BufferQueue& deleted_buffers,
368 const BufferQueue::iterator& next_buffer) {
369 DCHECK(!deleted_buffers.empty() && next_buffer != deleted_buffers.end());
370
371 SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
372
373 // Seek to the next keyframe after (or equal to) the timestamp of the next
374 // buffer being overlapped.
375 range_with_new_buffers->SeekAfter((*next_buffer)->GetTimestamp());
376 selected_range_ = range_with_new_buffers;
377
378 base::TimeDelta next_keyframe_timestamp =
379 range_with_new_buffers->GetNextTimestamp();
380
381 if (track_buffer_.empty()) {
382 // Add all the old buffers up until |next_keyframe_timestamp| into
383 // |track_buffer_|. If there was no next keyframe, then we add all buffers
384 // into |track_buffer_|.
385 BufferQueue::iterator next_buffer_itr = next_buffer;
386 while (next_buffer_itr != deleted_buffers.end() &&
387 (next_keyframe_timestamp == kNoTimestamp() ||
388 (*next_buffer_itr)->GetTimestamp() < next_keyframe_timestamp)) {
389 track_buffer_.push_back(*next_buffer_itr);
390 next_buffer_itr++;
391 }
392 }
393
394 // See if the next range contains the keyframe after the end of the
395 // |track_buffer_|, and if so, change |selected_range_|.
396 if (next_keyframe_timestamp == kNoTimestamp()) {
397 DCHECK(!track_buffer_.empty());
398 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
399 next_range_itr++;
400 if (next_range_itr != ranges_.end()) {
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 I don't think I really understand what is going on
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Close: the track buffer should never overlap with
401 (*next_range_itr)->SeekAfter(track_buffer_.back()->GetEndTimestamp());
402 if (IsNextInSequence(track_buffer_.back(),
403 (*next_range_itr)->GetNextTimestamp())) {
404 selected_range_ = *next_range_itr;
405 }
406 }
407 }
291 } 408 }
292 409
293 void SourceBufferStream::MergeWithAdjacentRangeIfNecessary( 410 void SourceBufferStream::MergeWithAdjacentRangeIfNecessary(
294 const RangeList::iterator& itr, SourceBufferRange* new_range) { 411 const RangeList::iterator& range_with_new_buffers_itr) {
295 if (itr != ranges_.end() && new_range->CanAppendToEnd(**itr)) { 412 SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
296 bool transfer_current_position = selected_range_ == *itr; 413 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
297 new_range->AppendToEnd(**itr, transfer_current_position); 414 next_range_itr++;
415
416 if (next_range_itr != ranges_.end() &&
417 range_with_new_buffers->CanAppendToEnd(**next_range_itr)) {
418 bool transfer_current_position = selected_range_ == *next_range_itr;
419 range_with_new_buffers->AppendToEnd(**next_range_itr,
420 transfer_current_position);
298 // Update |selected_range_| pointer if |range| has become selected after 421 // Update |selected_range_| pointer if |range| has become selected after
299 // merges. 422 // merges.
300 if (transfer_current_position) 423 if (transfer_current_position)
301 selected_range_ = new_range; 424 selected_range_ = range_with_new_buffers;
302 425
303 delete *itr; 426 delete *next_range_itr;
304 ranges_.erase(itr); 427 ranges_.erase(next_range_itr);
305 } 428 }
306 } 429 }
307 430
308 void SourceBufferStream::Seek(base::TimeDelta timestamp) { 431 void SourceBufferStream::Seek(base::TimeDelta timestamp) {
309 selected_range_ = NULL; 432 selected_range_ = NULL;
310 track_buffer_.clear(); 433 track_buffer_.clear();
311 waiting_for_keyframe_ = false;
312 434
313 seek_buffer_timestamp_ = timestamp; 435 seek_buffer_timestamp_ = timestamp;
314 seek_pending_ = true; 436 seek_pending_ = true;
315 437
316 RangeList::iterator itr = ranges_.end(); 438 RangeList::iterator itr = ranges_.end();
317 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) { 439 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) {
318 if ((*itr)->CanSeekTo(timestamp)) 440 if ((*itr)->CanSeekTo(timestamp))
319 break; 441 break;
320 } 442 }
321 443
(...skipping 18 matching lines...) Expand all
340 std::list<SourceBufferStream::Timespan> 462 std::list<SourceBufferStream::Timespan>
341 SourceBufferStream::GetBufferedTime() const { 463 SourceBufferStream::GetBufferedTime() const {
342 std::list<Timespan> timespans; 464 std::list<Timespan> timespans;
343 for (RangeList::const_iterator itr = ranges_.begin(); 465 for (RangeList::const_iterator itr = ranges_.begin();
344 itr != ranges_.end(); itr++) { 466 itr != ranges_.end(); itr++) {
345 timespans.push_back((*itr)->GetBufferedTime()); 467 timespans.push_back((*itr)->GetBufferedTime());
346 } 468 }
347 return timespans; 469 return timespans;
348 } 470 }
349 471
350 SourceBufferRange::SourceBufferRange() 472 SourceBufferRange::SourceBufferRange(const BufferQueue& new_buffers)
351 : next_buffer_index_(-1) { 473 : next_buffer_index_(-1),
352 } 474 waiting_for_keyframe_(false),
353 475 next_keyframe_timestamp_(kNoTimestamp()) {
354 void SourceBufferRange::Append(const BufferQueue& new_buffers) { 476 DCHECK(!new_buffers.empty());
355 base::TimeDelta start_timestamp = new_buffers.front()->GetTimestamp(); 477 DCHECK(new_buffers.front()->IsKeyframe());
356
357 if (!buffers_.empty() && start_timestamp < BufferedEnd()) {
358 // We are overwriting existing data, so find the starting point where
359 // things will get overwritten.
360 BufferQueue::iterator starting_point =
361 std::lower_bound(buffers_.begin(), buffers_.end(),
362 new_buffers.front(),
363 BufferComparator);
364
365 // Remove everything from |starting_point| onward.
366 buffers_.erase(starting_point, buffers_.end());
367 }
368
369 // Append data.
370 AppendToEnd(new_buffers); 478 AppendToEnd(new_buffers);
371 } 479 }
372 480
373 void SourceBufferRange::AppendToEnd(const BufferQueue& new_buffers) { 481 void SourceBufferRange::AppendToEnd(const BufferQueue& new_buffers) {
374 for (BufferQueue::const_iterator itr = new_buffers.begin(); 482 for (BufferQueue::const_iterator itr = new_buffers.begin();
375 itr != new_buffers.end(); itr++) { 483 itr != new_buffers.end(); itr++) {
376 DCHECK((*itr)->GetDuration() > base::TimeDelta()); 484 DCHECK((*itr)->GetDuration() > base::TimeDelta());
377 DCHECK((*itr)->GetTimestamp() != kNoTimestamp()); 485 DCHECK((*itr)->GetTimestamp() != kNoTimestamp());
378 buffers_.push_back(*itr); 486 buffers_.push_back(*itr);
379 if ((*itr)->IsKeyframe()) { 487 if ((*itr)->IsKeyframe()) {
380 keyframe_map_.insert( 488 keyframe_map_.insert(
381 std::make_pair((*itr)->GetTimestamp(), buffers_.size() - 1)); 489 std::make_pair((*itr)->GetTimestamp(), buffers_.size() - 1));
490
491 if (waiting_for_keyframe_ &&
492 (*itr)->GetTimestamp() >= next_keyframe_timestamp_) {
493 next_buffer_index_ = buffers_.size() - 1;
494 next_keyframe_timestamp_ = base::TimeDelta();
495 waiting_for_keyframe_ = false;
496 }
382 } 497 }
383 } 498 }
384 } 499 }
385 500
386 void SourceBufferRange::Seek(base::TimeDelta timestamp) { 501 void SourceBufferRange::Seek(base::TimeDelta timestamp) {
387 DCHECK(CanSeekTo(timestamp)); 502 DCHECK(CanSeekTo(timestamp));
388 DCHECK(!keyframe_map_.empty()); 503 DCHECK(!keyframe_map_.empty());
389 504
505 next_keyframe_timestamp_ = base::TimeDelta();
506 waiting_for_keyframe_ = false;
507
390 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp); 508 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp);
391 // lower_bound() returns the first element >= |timestamp|, so we want the 509 // lower_bound() returns the first element >= |timestamp|, so we want the
392 // previous element if it did not return the element exactly equal to 510 // previous element if it did not return the element exactly equal to
393 // |timestamp|. 511 // |timestamp|.
394 if (result == keyframe_map_.end() || result->first != timestamp) { 512 if (result == keyframe_map_.end() || result->first != timestamp) {
395 DCHECK(result != keyframe_map_.begin()); 513 DCHECK(result != keyframe_map_.begin());
396 result--; 514 result--;
397 } 515 }
398 next_buffer_index_ = result->second; 516 next_buffer_index_ = result->second;
399 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); 517 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size()));
400 } 518 }
401 519
402 base::TimeDelta SourceBufferRange::SeekAfter(base::TimeDelta timestamp) { 520 void SourceBufferRange::SeekAfter(base::TimeDelta timestamp) {
403 DCHECK_EQ(BelongsToRange(timestamp), 0);
404 DCHECK(!keyframe_map_.empty()); 521 DCHECK(!keyframe_map_.empty());
405 522
406 // lower_bound() returns the first element >= |timestamp|, so |result| is the 523 // lower_bound() returns the first element >= |timestamp|, so |result| is the
407 // value that we want. 524 // value that we want.
408 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp); 525 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp);
409 526
410 // If there isn't a keyframe after |timestamp|, then seek to end and return 527 // If there isn't a keyframe after |timestamp|, then seek to end and return
411 // kNoTimestamp to signal such. 528 // kNoTimestamp to signal such.
412 if (result == keyframe_map_.end()) { 529 if (result == keyframe_map_.end()) {
413 next_buffer_index_ = buffers_.size(); 530 waiting_for_keyframe_ = true;
414 return kNoTimestamp(); 531 next_buffer_index_ = -1;
532 next_keyframe_timestamp_ = timestamp;
533 return;
415 } 534 }
416 535
417 next_buffer_index_ = result->second; 536 next_buffer_index_ = result->second;
418 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); 537 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size()));
419 return result->first;
420 } 538 }
421 539
540 SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) {
541 // Find the first keyframe after |timestamp|.
542 KeyframeMap::iterator new_beginning_keyframe =
543 keyframe_map_.lower_bound(timestamp);
544
545 // If there is no keyframe after |timestamp|, we can't split the range.
546 if (new_beginning_keyframe == keyframe_map_.end())
547 return NULL;
548
549 int keyframe_index = new_beginning_keyframe->second;
550 DCHECK_LT(keyframe_index, static_cast<int>(buffers_.size()));
551
552 BufferQueue removed_buffers;
553 BufferQueue::iterator next_buffer;
554 DeleteAfter(
555 buffers_.begin() + keyframe_index, &removed_buffers, &next_buffer);
556
557 SourceBufferRange* split_range = new SourceBufferRange(removed_buffers);
558 if (next_buffer != removed_buffers.end()) {
559 split_range->next_buffer_index_ = next_buffer - removed_buffers.begin();
560 }
561 return split_range;
562 }
563
564 void SourceBufferRange::DeleteAll(BufferQueue* removed_buffers,
565 BufferQueue::iterator* next_buffer) {
566 DeleteAfter(buffers_.begin(), removed_buffers, next_buffer);
567 }
568
569 void SourceBufferRange::DeleteAfter(
570 scoped_refptr<StreamParserBuffer> buffer,
571 BufferQueue* removed_buffers,
572 BufferQueue::iterator* next_buffer) {
573 // Find the place in |buffers_| where we will begin deleting data.
574 BufferQueue::iterator starting_point =
575 std::lower_bound(buffers_.begin(), buffers_.end(),
576 buffer,
577 BufferComparator);
578 DeleteAfter(starting_point, removed_buffers, next_buffer);
579 }
580
581 void SourceBufferRange::DeleteAfter(
582 BufferQueue::iterator starting_point,
583 BufferQueue* removed_buffers,
584 BufferQueue::iterator* next_buffer) {
585 // Return if we're not deleting anything.
586 if (starting_point == buffers_.end())
587 return;
588
589 // Find the first keyframe after |starting_point|.
590 KeyframeMap::iterator starting_point_keyframe =
591 keyframe_map_.lower_bound((*starting_point)->GetTimestamp());
592
593 // Save the buffers we're about to delete.
594 if (removed_buffers) {
595 BufferQueue saved(starting_point, buffers_.end());
596 removed_buffers->swap(saved);
597 if (next_buffer)
598 *next_buffer = removed_buffers->end();
599 }
600
601 // Reset the next buffer index if we will be deleting the buffer that's next
602 // in sequence.
603 base::TimeDelta next_buffer_timestamp = GetNextTimestamp();
604 if (next_buffer_timestamp != kNoTimestamp() &&
605 next_buffer_timestamp >= (*starting_point)->GetTimestamp()) {
606 if (removed_buffers && next_buffer) {
607 int starting_offset = starting_point - buffers_.begin();
608 int next_buffer_offset = next_buffer_index_ - starting_offset;
609 DCHECK_GE(next_buffer_offset, 0);
610 *next_buffer = removed_buffers->begin() + next_buffer_offset;
611 }
612 next_buffer_index_ = -1;
613 }
614
615 // Remove keyframes from |starting_point| onward.
616 keyframe_map_.erase(starting_point_keyframe, keyframe_map_.end());
617
618 // Remove everything from |starting_point| onward.
619 buffers_.erase(starting_point, buffers_.end());
620 }
422 621
423 bool SourceBufferRange::GetNextBuffer( 622 bool SourceBufferRange::GetNextBuffer(
424 scoped_refptr<StreamParserBuffer>* out_buffer) { 623 scoped_refptr<StreamParserBuffer>* out_buffer) {
624 if (waiting_for_keyframe_ ||
625 next_buffer_index_ >= static_cast<int>(buffers_.size())) {
626 return false;
627 }
628
425 DCHECK_GE(next_buffer_index_, 0); 629 DCHECK_GE(next_buffer_index_, 0);
426 if (next_buffer_index_ >= static_cast<int>(buffers_.size()))
427 return false;
428
429 *out_buffer = buffers_.at(next_buffer_index_); 630 *out_buffer = buffers_.at(next_buffer_index_);
430 next_buffer_index_++; 631 next_buffer_index_++;
431 return true; 632 return true;
432 } 633 }
433 634
434 base::TimeDelta SourceBufferRange::GetNextTimestamp() const { 635 base::TimeDelta SourceBufferRange::GetNextTimestamp() const {
435 DCHECK_GE(next_buffer_index_, 0);
436 DCHECK(!buffers_.empty()); 636 DCHECK(!buffers_.empty());
437 637
438 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) 638 if (next_buffer_index_ >= static_cast<int>(buffers_.size()) ||
439 return buffers_.back()->GetEndTimestamp(); 639 next_buffer_index_ < 0 || waiting_for_keyframe_) {
640 return kNoTimestamp();
641 }
440 642
441 return buffers_.at(next_buffer_index_)->GetTimestamp(); 643 return buffers_.at(next_buffer_index_)->GetTimestamp();
442 } 644 }
443 645
646 base::TimeDelta SourceBufferRange::GetEndTimestamp() const {
647 return BufferedEnd();
acolwell GONE FROM CHROMIUM 2012/05/22 19:35:23 nit: One of these two methods should be removed si
vrk (LEFT CHROMIUM) 2012/05/24 20:06:30 Done.
648 }
649
444 SourceBufferStream::Timespan 650 SourceBufferStream::Timespan
445 SourceBufferRange::GetBufferedTime() const { 651 SourceBufferRange::GetBufferedTime() const {
446 return std::make_pair(BufferedStart(), BufferedEnd()); 652 return std::make_pair(BufferedStart(), BufferedEnd());
447 } 653 }
448 654
449 void SourceBufferRange::AppendToEnd(const SourceBufferRange& range, 655 void SourceBufferRange::AppendToEnd(const SourceBufferRange& range,
450 bool transfer_current_position) { 656 bool transfer_current_position) {
451 DCHECK(CanAppendToEnd(range)); 657 DCHECK(CanAppendToEnd(range));
452 DCHECK(!buffers_.empty()); 658 DCHECK(!buffers_.empty());
453 659
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 const SourceBufferRange& range) const { 697 const SourceBufferRange& range) const {
492 return BufferedStart() <= range.BufferedStart() && 698 return BufferedStart() <= range.BufferedStart() &&
493 BufferedEnd() >= range.BufferedEnd(); 699 BufferedEnd() >= range.BufferedEnd();
494 } 700 }
495 701
496 bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const { 702 bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const {
497 return range.BufferedStart() < BufferedEnd() && 703 return range.BufferedStart() < BufferedEnd() &&
498 BufferedEnd() < range.BufferedEnd(); 704 BufferedEnd() < range.BufferedEnd();
499 } 705 }
500 706
501 bool SourceBufferRange::IsStartOverlappedBy(const BufferQueue& buffers) const {
502 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp();
503 return BufferedStart() < start_timestamp && start_timestamp < BufferedEnd();
504 }
505
506 bool SourceBufferRange::IsEndOverlappedBy(const BufferQueue& buffers) const {
507 base::TimeDelta end_timestamp = buffers.back()->GetEndTimestamp();
508 return BufferedStart() < end_timestamp && end_timestamp < BufferedEnd();
509 }
510
511 bool SourceBufferRange::IsCompletelyOverlappedBy(
512 const BufferQueue& buffers) const {
513 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp();
514 base::TimeDelta end_timestamp = buffers.back()->GetEndTimestamp();
515 return start_timestamp <= BufferedStart() && BufferedEnd() <= end_timestamp;
516 }
517
518 base::TimeDelta SourceBufferRange::BufferedStart() const { 707 base::TimeDelta SourceBufferRange::BufferedStart() const {
519 if (buffers_.empty()) 708 if (buffers_.empty())
520 return kNoTimestamp(); 709 return kNoTimestamp();
521
522 return buffers_.front()->GetTimestamp(); 710 return buffers_.front()->GetTimestamp();
523 } 711 }
524 712
525 base::TimeDelta SourceBufferRange::BufferedEnd() const { 713 base::TimeDelta SourceBufferRange::BufferedEnd() const {
526 if (buffers_.empty()) 714 if (buffers_.empty())
527 return kNoTimestamp(); 715 return kNoTimestamp();
528
529 return buffers_.back()->GetEndTimestamp(); 716 return buffers_.back()->GetEndTimestamp();
530 } 717 }
531 718
532 } // namespace media 719 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698