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

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: Response to CR 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
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 explicit SourceBufferRange(const BufferQueue& new_buffers);
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_index_|
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 at |next_buffer_index_| was
58 // deleted, and deletes the |keyframe_map_| entries for the buffers that
59 // were removed.
60 // If |deleted_buffers| or |next_buffer| are null, they are ignored.
61 // Otherwise, |deleted_buffers| contains the buffers that were deleted from
62 // this range, and |next_buffer| points to the buffer in |deleted_buffers|
63 // that had been at |next_buffer_index_|. If |next_buffer_index_| did not
64 // point to any buffer added to |deleted_buffers|, then |next_buffer| points
65 // to |deleted_buffers.end()|.
66 void DeleteAfter(scoped_refptr<StreamParserBuffer> buffer,
67 BufferQueue* deleted_buffers,
68 BufferQueue::iterator* next_buffer);
69 // Deletes all buffers in range.
70 void DeleteAll(BufferQueue* deleted_buffers,
71 BufferQueue::iterator* next_buffer);
36 72
37 // Updates |out_buffer| with the next buffer in presentation order. Seek() 73 // Updates |out_buffer| with the next buffer in presentation order. Seek()
38 // must be called before calls to GetNextBuffer(), and buffers are returned 74 // 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 75 // 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 76 // filled with a valid buffer, false if there is not enough data to fulfill
41 // the request. 77 // the request.
42 bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer); 78 bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer);
79
80 // Returns the timestamp of the next buffer that will be returned from
81 // GetNextBuffer(). Returns kNoTimestamp() if Seek() has never been called or
82 // if this range does not have the next buffer yet.
43 base::TimeDelta GetNextTimestamp() const; 83 base::TimeDelta GetNextTimestamp() const;
44 84
85 // Returns the end timestamp of the buffered data. (Note that this is equal to
86 // the last buffer's timestamp + its duration.)
87 base::TimeDelta GetEndTimestamp() const;
88
45 // Returns the Timespan of buffered time in this range. 89 // Returns the Timespan of buffered time in this range.
46 SourceBufferStream::Timespan GetBufferedTime() const; 90 SourceBufferStream::Timespan GetBufferedTime() const;
47 91
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 92 // 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 93 // belong in this range. This includes a buffer that would be appended to
60 // the end of the range. 94 // the end of the range.
61 // Returns 0 if |timestamp| is in this range, -1 if |timestamp| appears 95 // Returns 0 if |timestamp| is in this range, -1 if |timestamp| appears
62 // before this range, or 1 if |timestamp| appears after this range. 96 // before this range, or 1 if |timestamp| appears after this range.
63 int BelongsToRange(base::TimeDelta timestamp) const; 97 int BelongsToRange(base::TimeDelta timestamp) const;
64 98
65 // Returns true if the range has enough data to seek to the specified 99 // Returns true if the range has enough data to seek to the specified
66 // |timestamp|, false otherwise. 100 // |timestamp|, false otherwise.
67 bool CanSeekTo(base::TimeDelta timestamp) const; 101 bool CanSeekTo(base::TimeDelta timestamp) const;
68 102
69 // Returns true if this range's buffered timespan completely overlaps the 103 // Returns true if this range's buffered timespan completely overlaps the
70 // buffered timespan of |range|. 104 // buffered timespan of |range|.
71 bool CompletelyOverlaps(const SourceBufferRange& range) const; 105 bool CompletelyOverlaps(const SourceBufferRange& range) const;
72 106
73 // Returns true if the end of this range contains buffers that overlaps with 107 // Returns true if the end of this range contains buffers that overlaps with
74 // the beginning of |range|. 108 // the beginning of |range|.
75 bool EndOverlaps(const SourceBufferRange& range) const; 109 bool EndOverlaps(const SourceBufferRange& range) const;
76 110
77 // Functions that tell how |buffers| intersects with this range. 111 private:
78 // TODO(vrk): These functions should be unnecessary when overlapping the 112 // Helper method to delete buffers in |buffers_| starting from
79 // selected range is implemented properly. (crbug.com/126560) 113 // |starting_point|, an iterator in |buffers_|.
80 bool IsStartOverlappedBy(const BufferQueue& buffers) const; 114 void DeleteAfter(BufferQueue::iterator starting_point,
81 bool IsEndOverlappedBy(const BufferQueue& buffers) const; 115 BufferQueue* deleted_buffers,
82 bool IsCompletelyOverlappedBy(const BufferQueue& buffers) const; 116 BufferQueue::iterator* next_buffer);
83 117
84 private: 118 // Returns the start timestamp of the range.
85 // Appends |buffers| to the end of the range and updates |keyframe_map_| as 119 base::TimeDelta GetStartTimestamp() const;
86 // it encounters new keyframes. Assumes |buffers| belongs at the end of the
87 // range.
88 void AppendToEnd(const BufferQueue& buffers);
89
90 // Returns the start timestamp of the range, or kNoTimestamp if the range is
91 // empty.
92 base::TimeDelta BufferedStart() const;
93
94 // 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
96 // range is empty.
97 base::TimeDelta BufferedEnd() const;
98 120
99 // An ordered list of buffers in this range. 121 // An ordered list of buffers in this range.
100 BufferQueue buffers_; 122 BufferQueue buffers_;
101 123
102 // Maps keyframe timestamps to its index position in |buffers_|. 124 // Maps keyframe timestamps to its index position in |buffers_|.
103 typedef std::map<base::TimeDelta, size_t> KeyframeMap; 125 typedef std::map<base::TimeDelta, size_t> KeyframeMap;
104 KeyframeMap keyframe_map_; 126 KeyframeMap keyframe_map_;
105 127
106 // Index into |buffers_| for the next buffer to be returned by 128 // Index into |buffers_| for the next buffer to be returned by
107 // GetBufferedTime(), set to -1 before Seek(). 129 // GetBufferedTime(), set to -1 before Seek().
108 int next_buffer_index_; 130 int next_buffer_index_;
109 131
132 // True if the range needs to wait for the next keyframe to be appended before
133 // returning buffers from GetNextBuffer().
134 bool waiting_for_keyframe_;
135
136 // If |waiting_for_keyframe_| is true, this range will wait for the next
137 // keyframe with timestamp >= |next_keyframe_timestamp_|.
138 base::TimeDelta next_keyframe_timestamp_;
139
110 DISALLOW_COPY_AND_ASSIGN(SourceBufferRange); 140 DISALLOW_COPY_AND_ASSIGN(SourceBufferRange);
111 }; 141 };
112 142
113 } // namespace media 143 } // namespace media
114 144
115 // Helper method that returns true if |ranges| is sorted in increasing order, 145 // Helper method that returns true if |ranges| is sorted in increasing order,
116 // false otherwise. 146 // false otherwise.
117 static bool IsRangeListSorted( 147 static bool IsRangeListSorted(
118 const std::list<media::SourceBufferRange*>& ranges) { 148 const std::list<media::SourceBufferRange*>& ranges) {
119 base::TimeDelta prev = media::kNoTimestamp(); 149 base::TimeDelta prev = media::kNoTimestamp();
120 for (std::list<media::SourceBufferRange*>::const_iterator itr = 150 for (std::list<media::SourceBufferRange*>::const_iterator itr =
121 ranges.begin(); itr != ranges.end(); itr++) { 151 ranges.begin(); itr != ranges.end(); itr++) {
122 media::SourceBufferStream::Timespan buffered = (*itr)->GetBufferedTime(); 152 media::SourceBufferStream::Timespan buffered = (*itr)->GetBufferedTime();
123 if (prev != media::kNoTimestamp() && prev >= buffered.first) 153 if (prev != media::kNoTimestamp() && prev >= buffered.first)
124 return false; 154 return false;
125 prev = buffered.second; 155 prev = buffered.second;
126 } 156 }
127 return true; 157 return true;
128 } 158 }
129 159
130 // Comparison function for two Buffers based on timestamp. 160 // Comparison function for two Buffers based on timestamp.
131 static bool BufferComparator(scoped_refptr<media::Buffer> first, 161 static bool BufferComparator(
132 scoped_refptr<media::Buffer> second) { 162 const scoped_refptr<media::StreamParserBuffer>& first,
163 const scoped_refptr<media::StreamParserBuffer>& second) {
133 return first->GetTimestamp() < second->GetTimestamp(); 164 return first->GetTimestamp() < second->GetTimestamp();
134 } 165 }
135 166
136 // Returns the upper bound for the starting timestamp for the next buffer 167 // Returns the upper bound for the starting timestamp for the next buffer
137 // in sequence after |buffer|. Assumes |buffer|'s timestamp and 168 // in sequence after |buffer|. Assumes |buffer|'s timestamp and
138 // duration are valid. 169 // duration are valid.
139 static base::TimeDelta MaxNextTimestamp( 170 static base::TimeDelta MaxNextTimestamp(
140 const scoped_refptr<media::StreamParserBuffer>& buffer) { 171 const scoped_refptr<media::StreamParserBuffer>& buffer) {
141 // Because we do not know exactly when is the next timestamp, any buffer 172 // 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 173 // that starts within 1/3 of the duration past the end of this buffer
143 // is considered the next buffer in the sequence. 174 // is considered the next buffer in the sequence.
144 return buffer->GetEndTimestamp() + buffer->GetDuration() / 3; 175 return buffer->GetEndTimestamp() + buffer->GetDuration() / 3;
145 } 176 }
146 177
147 // Returns true if |timestamp| is the timestamp of the next buffer in 178 // Returns true if |timestamp| is the timestamp of the next buffer in
148 // sequence after |buffer|, false otherwise. 179 // sequence after |buffer|, false otherwise.
149 static bool IsNextInSequence( 180 static bool IsNextInSequence(
150 const scoped_refptr<media::StreamParserBuffer>& buffer, 181 const scoped_refptr<media::StreamParserBuffer>& buffer,
151 base::TimeDelta timestamp) { 182 base::TimeDelta timestamp) {
152 return timestamp >= buffer->GetEndTimestamp() && 183 return timestamp >= buffer->GetEndTimestamp() &&
153 timestamp <= MaxNextTimestamp(buffer); 184 timestamp <= MaxNextTimestamp(buffer);
154 } 185 }
155 186
156 namespace media { 187 namespace media {
157 188
158 SourceBufferStream::SourceBufferStream() 189 SourceBufferStream::SourceBufferStream()
159 : seek_pending_(false), 190 : seek_pending_(false),
160 seek_buffer_timestamp_(kNoTimestamp()), 191 seek_buffer_timestamp_(kNoTimestamp()),
161 selected_range_(NULL), 192 selected_range_(NULL) {
162 waiting_for_keyframe_(false) {
163 } 193 }
164 194
165 SourceBufferStream::~SourceBufferStream() { 195 SourceBufferStream::~SourceBufferStream() {
166 while (!ranges_.empty()) { 196 while (!ranges_.empty()) {
167 delete ranges_.front(); 197 delete ranges_.front();
168 ranges_.pop_front(); 198 ranges_.pop_front();
169 } 199 }
170 } 200 }
171 201
172 bool SourceBufferStream::Append( 202 bool SourceBufferStream::Append(
173 const SourceBufferStream::BufferQueue& buffers) { 203 const SourceBufferStream::BufferQueue& buffers) {
174 DCHECK(!buffers.empty()); 204 DCHECK(!buffers.empty());
175 205
176 // Check to see if |buffers| will overlap the currently |selected_range_|, 206 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(); 207 RangeList::iterator itr = ranges_.end();
187 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp(); 208 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp();
188 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) { 209 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) {
189 int range_value = (*itr)->BelongsToRange(start_timestamp); 210 int range_value = (*itr)->BelongsToRange(start_timestamp);
190 211 if (range_value < 0)
acolwell GONE FROM CHROMIUM 2012/05/24 22:21:00 nit: Keep the "|start_timestamp| is before the cur
vrk (LEFT CHROMIUM) 2012/05/25 15:48:08 Done.
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; 212 break;
200 213
201 if (range_value == 0) { 214 if (range_value == 0) {
202 // Found an existing range into which we can append buffers. 215 // Found an existing range into which we can append buffers.
203 range = *itr; 216 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; 217 break;
213 } 218 }
214 } 219 }
215 220
216 if (!range) { 221 if (range_for_new_buffers == ranges_.end()) {
217 // Ranges must begin with a keyframe. 222 // Ranges must begin with a keyframe.
218 if (!buffers.front()->IsKeyframe()) 223 if (!buffers.front()->IsKeyframe())
219 return false; 224 return false;
220 225 range_for_new_buffers =
221 range = new SourceBufferRange(); 226 ranges_.insert(itr, new SourceBufferRange(buffers));
222 itr = ranges_.insert(itr, range); 227 } else {
228 InsertIntoExistingRange(range_for_new_buffers, buffers);
223 } 229 }
224 230
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. 231 // Resolve overlaps.
232 itr = ResolveCompleteOverlaps(itr, range); 232 ResolveCompleteOverlaps(range_for_new_buffers);
233 itr = ResolveEndOverlaps(itr, range); 233 ResolveEndOverlap(range_for_new_buffers);
234 MergeWithAdjacentRangeIfNecessary(itr, range); 234 MergeWithAdjacentRangeIfNecessary(range_for_new_buffers);
235 235
236 // Finally, try to complete pending seek if one exists. 236 // Finally, try to complete pending seek if one exists.
237 if (seek_pending_) 237 if (seek_pending_)
238 Seek(seek_buffer_timestamp_); 238 Seek(seek_buffer_timestamp_);
239 239
240 DCHECK(IsRangeListSorted(ranges_)); 240 DCHECK(IsRangeListSorted(ranges_));
241 return true; 241 return true;
242 } 242 }
243 243
244 SourceBufferStream::RangeList::iterator 244 void SourceBufferStream::InsertIntoExistingRange(
245 SourceBufferStream::ResolveCompleteOverlaps( 245 const RangeList::iterator& range_for_new_buffers_itr,
246 const RangeList::iterator& range_itr, SourceBufferRange* new_range) { 246 const BufferQueue& new_buffers) {
247 RangeList::iterator itr = range_itr; 247 SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr;
248 while (itr != ranges_.end() && new_range->CompletelyOverlaps(**itr)) { 248 RangeList::iterator next_range_itr = range_for_new_buffers_itr;
249 if (*itr == selected_range_) { 249 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 250
258 // If there's no keyframe after |next_timestamp|, then set flag to wait 251 // 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. 252 // of |new_buffers|, and add them into a new range.
260 if (next_keyframe_timestamp == kNoTimestamp()) 253 SourceBufferRange* new_portion =
261 waiting_for_keyframe_ = true; 254 range_for_new_buffers->SplitRange(new_buffers.back()->GetEndTimestamp());
262 255
263 // Add all the old buffers up until |next_keyframe_timestamp| into 256 if (new_portion) {
264 // |track_buffer_|. If there was no keyframe, then we add all buffers into 257 next_range_itr = ranges_.insert(next_range_itr, new_portion);
265 // |track_buffer_|. 258 // If |range_for_new_buffers| was selected and the next buffer was in the
266 scoped_refptr<StreamParserBuffer> next_buffer; 259 // |new_portion| half, update |selected_range_|.
267 while (selected_range_->GetNextBuffer(&next_buffer) && 260 if (selected_range_ == range_for_new_buffers &&
268 (waiting_for_keyframe_ || 261 new_portion->GetNextTimestamp() != kNoTimestamp()) {
269 next_buffer->GetTimestamp() < next_keyframe_timestamp)) { 262 selected_range_ = new_portion;
270 track_buffer_.push_back(next_buffer); 263 }
271 } 264 }
272 265
273 selected_range_ = new_range; 266 BufferQueue deleted_buffers;
274 } 267 BufferQueue::iterator next_buffer;
275 delete *itr; 268 range_for_new_buffers->DeleteAfter(
276 itr = ranges_.erase(itr); 269 new_buffers.front(), &deleted_buffers, &next_buffer);
270 range_for_new_buffers->AppendToEnd(new_buffers);
271
272 if (selected_range_ == range_for_new_buffers &&
273 !deleted_buffers.empty() && next_buffer != deleted_buffers.end()) {
274 UpdateTrackBuffer(range_for_new_buffers_itr, deleted_buffers, next_buffer);
277 } 275 }
278 return itr;
279 } 276 }
280 277
281 SourceBufferStream::RangeList::iterator 278 void SourceBufferStream::ResolveCompleteOverlaps(
282 SourceBufferStream::ResolveEndOverlaps( 279 const RangeList::iterator& range_with_new_buffers_itr) {
283 const RangeList::iterator& range_itr, SourceBufferRange* new_range) { 280 SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
284 RangeList::iterator itr = range_itr; 281 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
285 while (itr != ranges_.end() && new_range->EndOverlaps(**itr)) { 282 next_range_itr++;
286 DCHECK_NE(*itr, selected_range_); 283
287 delete *itr; 284 while (next_range_itr != ranges_.end() &&
288 itr = ranges_.erase(itr); 285 range_with_new_buffers->CompletelyOverlaps(**next_range_itr)) {
286 if (*next_range_itr == selected_range_) {
287 // Delete everything from the selected range that |new_range| overlaps,
288 // and save the next buffers.
289 BufferQueue deleted_buffers;
290 BufferQueue::iterator next_buffer;
291 (*next_range_itr)->DeleteAll(&deleted_buffers, &next_buffer);
292 UpdateTrackBuffer(range_with_new_buffers_itr, deleted_buffers,
293 next_buffer);
294 DCHECK_NE(selected_range_, *next_range_itr);
295 }
296 delete *next_range_itr;
297 next_range_itr = ranges_.erase(next_range_itr);
289 } 298 }
290 return itr; 299 }
300
301 void SourceBufferStream::ResolveEndOverlap(
302 const RangeList::iterator& range_with_new_buffers_itr) {
303 SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
304 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
305 next_range_itr++;
306
307 if (next_range_itr == ranges_.end() ||
308 !range_with_new_buffers->EndOverlaps(**next_range_itr)) {
309 return;
310 }
311
312 // Split the overlapped range after |range_with_new_buffers|'s last buffer
313 // overlaps. Now |overlapped_range| contains only the buffers that do not
314 // belong in |ranges_| anymore, and |new_next_range| contains buffers that
315 // go after |range_with_new_buffers| (without overlap).
316 scoped_ptr<SourceBufferRange> overlapped_range(*next_range_itr);
317 next_range_itr = ranges_.erase(next_range_itr);
318
319 SourceBufferRange* new_next_range =
320 overlapped_range->SplitRange(range_with_new_buffers->GetEndTimestamp());
321
322 // If there were non-overlapped buffers, add the new range to |ranges_|.
323 if (new_next_range)
324 ranges_.insert(next_range_itr, new_next_range);
325
326 // If we didn't overlap a selected range, return.
327 if (selected_range_ != overlapped_range.get())
328 return;
329
330 // If the next buffer was in the |new_next_range| half of the overlapped
331 // range, then the |selected_range_| is now |new_next_range|.
332 if (new_next_range &&
333 new_next_range->GetNextTimestamp() != kNoTimestamp()) {
334 selected_range_ = new_next_range;
335 return;
336 }
337
338 // Otherwise, update track buffer with overlapped buffers.
339 BufferQueue deleted_buffers;
340 scoped_refptr<StreamParserBuffer> buffer;
341 while (overlapped_range->GetNextBuffer(&buffer)) {
342 deleted_buffers.push_back(buffer);
343 }
344 BufferQueue::iterator next_buffer = deleted_buffers.begin();
345
346 // This will update |selected_range_| to no longer point to
347 // |overlapped_range|.
348 UpdateTrackBuffer(range_with_new_buffers_itr, deleted_buffers, next_buffer);
349 DCHECK_NE(selected_range_, overlapped_range.get());
350 }
351
352 void SourceBufferStream::UpdateTrackBuffer(
353 const RangeList::iterator& range_with_new_buffers_itr,
354 const BufferQueue& deleted_buffers,
355 const BufferQueue::iterator& next_buffer) {
356 DCHECK(!deleted_buffers.empty() && next_buffer != deleted_buffers.end());
357
358 SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
359
360 // Seek to the next keyframe after (or equal to) the timestamp of the next
361 // buffer being overlapped.
362 range_with_new_buffers->SeekAfter((*next_buffer)->GetTimestamp());
363 selected_range_ = range_with_new_buffers;
364
365 base::TimeDelta next_keyframe_timestamp =
366 range_with_new_buffers->GetNextTimestamp();
367
368 if (track_buffer_.empty()) {
369 // Add all the old buffers up until |next_keyframe_timestamp| into
370 // |track_buffer_|. If there was no next keyframe, then we add all buffers
371 // into |track_buffer_|.
372 BufferQueue::iterator next_buffer_itr = next_buffer;
373 while (next_buffer_itr != deleted_buffers.end() &&
374 (next_keyframe_timestamp == kNoTimestamp() ||
375 (*next_buffer_itr)->GetTimestamp() < next_keyframe_timestamp)) {
376 track_buffer_.push_back(*next_buffer_itr);
377 next_buffer_itr++;
378 }
379 }
380
381 // See if the next range contains the keyframe after the end of the
382 // |track_buffer_|, and if so, change |selected_range_|.
383 if (next_keyframe_timestamp == kNoTimestamp()) {
384 DCHECK(!track_buffer_.empty());
385 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
386 next_range_itr++;
387 if (next_range_itr != ranges_.end()) {
388 (*next_range_itr)->SeekAfter(track_buffer_.back()->GetEndTimestamp());
389 if (IsNextInSequence(track_buffer_.back(),
390 (*next_range_itr)->GetNextTimestamp())) {
391 selected_range_ = *next_range_itr;
392 }
393 }
394 }
291 } 395 }
292 396
293 void SourceBufferStream::MergeWithAdjacentRangeIfNecessary( 397 void SourceBufferStream::MergeWithAdjacentRangeIfNecessary(
294 const RangeList::iterator& itr, SourceBufferRange* new_range) { 398 const RangeList::iterator& range_with_new_buffers_itr) {
295 if (itr != ranges_.end() && new_range->CanAppendToEnd(**itr)) { 399 SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
296 bool transfer_current_position = selected_range_ == *itr; 400 RangeList::iterator next_range_itr = range_with_new_buffers_itr;
297 new_range->AppendToEnd(**itr, transfer_current_position); 401 next_range_itr++;
402
403 if (next_range_itr != ranges_.end() &&
404 range_with_new_buffers->CanAppendToEnd(**next_range_itr)) {
405 bool transfer_current_position = selected_range_ == *next_range_itr;
406 range_with_new_buffers->AppendToEnd(**next_range_itr,
407 transfer_current_position);
298 // Update |selected_range_| pointer if |range| has become selected after 408 // Update |selected_range_| pointer if |range| has become selected after
299 // merges. 409 // merges.
300 if (transfer_current_position) 410 if (transfer_current_position)
301 selected_range_ = new_range; 411 selected_range_ = range_with_new_buffers;
302 412
303 delete *itr; 413 delete *next_range_itr;
304 ranges_.erase(itr); 414 ranges_.erase(next_range_itr);
305 } 415 }
306 } 416 }
307 417
308 void SourceBufferStream::Seek(base::TimeDelta timestamp) { 418 void SourceBufferStream::Seek(base::TimeDelta timestamp) {
309 selected_range_ = NULL; 419 selected_range_ = NULL;
310 track_buffer_.clear(); 420 track_buffer_.clear();
311 waiting_for_keyframe_ = false;
312 421
313 seek_buffer_timestamp_ = timestamp; 422 seek_buffer_timestamp_ = timestamp;
314 seek_pending_ = true; 423 seek_pending_ = true;
315 424
316 RangeList::iterator itr = ranges_.end(); 425 RangeList::iterator itr = ranges_.end();
317 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) { 426 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) {
318 if ((*itr)->CanSeekTo(timestamp)) 427 if ((*itr)->CanSeekTo(timestamp))
319 break; 428 break;
320 } 429 }
321 430
(...skipping 18 matching lines...) Expand all
340 std::list<SourceBufferStream::Timespan> 449 std::list<SourceBufferStream::Timespan>
341 SourceBufferStream::GetBufferedTime() const { 450 SourceBufferStream::GetBufferedTime() const {
342 std::list<Timespan> timespans; 451 std::list<Timespan> timespans;
343 for (RangeList::const_iterator itr = ranges_.begin(); 452 for (RangeList::const_iterator itr = ranges_.begin();
344 itr != ranges_.end(); itr++) { 453 itr != ranges_.end(); itr++) {
345 timespans.push_back((*itr)->GetBufferedTime()); 454 timespans.push_back((*itr)->GetBufferedTime());
346 } 455 }
347 return timespans; 456 return timespans;
348 } 457 }
349 458
350 SourceBufferRange::SourceBufferRange() 459 SourceBufferRange::SourceBufferRange(const BufferQueue& new_buffers)
351 : next_buffer_index_(-1) { 460 : next_buffer_index_(-1),
352 } 461 waiting_for_keyframe_(false),
353 462 next_keyframe_timestamp_(kNoTimestamp()) {
354 void SourceBufferRange::Append(const BufferQueue& new_buffers) { 463 DCHECK(!new_buffers.empty());
355 base::TimeDelta start_timestamp = new_buffers.front()->GetTimestamp(); 464 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); 465 AppendToEnd(new_buffers);
371 } 466 }
372 467
373 void SourceBufferRange::AppendToEnd(const BufferQueue& new_buffers) { 468 void SourceBufferRange::AppendToEnd(const BufferQueue& new_buffers) {
374 for (BufferQueue::const_iterator itr = new_buffers.begin(); 469 for (BufferQueue::const_iterator itr = new_buffers.begin();
375 itr != new_buffers.end(); itr++) { 470 itr != new_buffers.end(); itr++) {
376 DCHECK((*itr)->GetDuration() > base::TimeDelta()); 471 DCHECK((*itr)->GetDuration() > base::TimeDelta());
377 DCHECK((*itr)->GetTimestamp() != kNoTimestamp()); 472 DCHECK((*itr)->GetTimestamp() != kNoTimestamp());
378 buffers_.push_back(*itr); 473 buffers_.push_back(*itr);
379 if ((*itr)->IsKeyframe()) { 474 if ((*itr)->IsKeyframe()) {
380 keyframe_map_.insert( 475 keyframe_map_.insert(
381 std::make_pair((*itr)->GetTimestamp(), buffers_.size() - 1)); 476 std::make_pair((*itr)->GetTimestamp(), buffers_.size() - 1));
477
478 if (waiting_for_keyframe_ &&
479 (*itr)->GetTimestamp() >= next_keyframe_timestamp_) {
480 next_buffer_index_ = buffers_.size() - 1;
481 next_keyframe_timestamp_ = base::TimeDelta();
482 waiting_for_keyframe_ = false;
483 }
382 } 484 }
383 } 485 }
384 } 486 }
385 487
386 void SourceBufferRange::Seek(base::TimeDelta timestamp) { 488 void SourceBufferRange::Seek(base::TimeDelta timestamp) {
387 DCHECK(CanSeekTo(timestamp)); 489 DCHECK(CanSeekTo(timestamp));
388 DCHECK(!keyframe_map_.empty()); 490 DCHECK(!keyframe_map_.empty());
389 491
492 next_keyframe_timestamp_ = base::TimeDelta();
493 waiting_for_keyframe_ = false;
494
390 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp); 495 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp);
391 // lower_bound() returns the first element >= |timestamp|, so we want the 496 // lower_bound() returns the first element >= |timestamp|, so we want the
392 // previous element if it did not return the element exactly equal to 497 // previous element if it did not return the element exactly equal to
393 // |timestamp|. 498 // |timestamp|.
394 if (result == keyframe_map_.end() || result->first != timestamp) { 499 if (result == keyframe_map_.end() || result->first != timestamp) {
395 DCHECK(result != keyframe_map_.begin()); 500 DCHECK(result != keyframe_map_.begin());
396 result--; 501 result--;
397 } 502 }
398 next_buffer_index_ = result->second; 503 next_buffer_index_ = result->second;
399 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); 504 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size()));
400 } 505 }
401 506
402 base::TimeDelta SourceBufferRange::SeekAfter(base::TimeDelta timestamp) { 507 void SourceBufferRange::SeekAfter(base::TimeDelta timestamp) {
403 DCHECK_EQ(BelongsToRange(timestamp), 0);
404 DCHECK(!keyframe_map_.empty()); 508 DCHECK(!keyframe_map_.empty());
405 509
406 // lower_bound() returns the first element >= |timestamp|, so |result| is the 510 // lower_bound() returns the first element >= |timestamp|, so |result| is the
407 // value that we want. 511 // value that we want.
408 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp); 512 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp);
409 513
410 // If there isn't a keyframe after |timestamp|, then seek to end and return 514 // If there isn't a keyframe after |timestamp|, then seek to end and return
411 // kNoTimestamp to signal such. 515 // kNoTimestamp to signal such.
412 if (result == keyframe_map_.end()) { 516 if (result == keyframe_map_.end()) {
413 next_buffer_index_ = buffers_.size(); 517 waiting_for_keyframe_ = true;
414 return kNoTimestamp(); 518 next_buffer_index_ = -1;
519 next_keyframe_timestamp_ = timestamp;
520 return;
415 } 521 }
416 522
417 next_buffer_index_ = result->second; 523 next_buffer_index_ = result->second;
418 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); 524 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size()));
419 return result->first;
420 } 525 }
421 526
527 SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) {
528 // Find the first keyframe after |timestamp|.
529 KeyframeMap::iterator new_beginning_keyframe =
530 keyframe_map_.lower_bound(timestamp);
531
532 // If there is no keyframe after |timestamp|, we can't split the range.
533 if (new_beginning_keyframe == keyframe_map_.end())
534 return NULL;
535
536 int keyframe_index = new_beginning_keyframe->second;
537 DCHECK_LT(keyframe_index, static_cast<int>(buffers_.size()));
538
539 BufferQueue removed_buffers;
540 BufferQueue::iterator next_buffer;
541 DeleteAfter(
542 buffers_.begin() + keyframe_index, &removed_buffers, &next_buffer);
543
544 SourceBufferRange* split_range = new SourceBufferRange(removed_buffers);
545 if (next_buffer != removed_buffers.end()) {
546 split_range->next_buffer_index_ = next_buffer - removed_buffers.begin();
547 }
548 return split_range;
549 }
550
551 void SourceBufferRange::DeleteAll(BufferQueue* removed_buffers,
552 BufferQueue::iterator* next_buffer) {
553 DeleteAfter(buffers_.begin(), removed_buffers, next_buffer);
554 }
555
556 void SourceBufferRange::DeleteAfter(
557 scoped_refptr<StreamParserBuffer> buffer,
558 BufferQueue* removed_buffers,
559 BufferQueue::iterator* next_buffer) {
560 // Find the place in |buffers_| where we will begin deleting data.
561 BufferQueue::iterator starting_point =
562 std::lower_bound(buffers_.begin(), buffers_.end(),
563 buffer,
564 BufferComparator);
565 DeleteAfter(starting_point, removed_buffers, next_buffer);
566 }
567
568 void SourceBufferRange::DeleteAfter(
569 BufferQueue::iterator starting_point,
570 BufferQueue* removed_buffers,
571 BufferQueue::iterator* next_buffer) {
572 // Return if we're not deleting anything.
573 if (starting_point == buffers_.end())
574 return;
575
576 // Find the first keyframe after |starting_point|.
577 KeyframeMap::iterator starting_point_keyframe =
578 keyframe_map_.lower_bound((*starting_point)->GetTimestamp());
579
580 // Save the buffers we're about to delete.
581 if (removed_buffers) {
582 BufferQueue saved(starting_point, buffers_.end());
583 removed_buffers->swap(saved);
584 if (next_buffer)
585 *next_buffer = removed_buffers->end();
586 }
587
588 // Reset the next buffer index if we will be deleting the buffer that's next
589 // in sequence.
590 base::TimeDelta next_buffer_timestamp = GetNextTimestamp();
591 if (next_buffer_timestamp != kNoTimestamp() &&
592 next_buffer_timestamp >= (*starting_point)->GetTimestamp()) {
593 if (removed_buffers && next_buffer) {
594 int starting_offset = starting_point - buffers_.begin();
595 int next_buffer_offset = next_buffer_index_ - starting_offset;
596 DCHECK_GE(next_buffer_offset, 0);
597 *next_buffer = removed_buffers->begin() + next_buffer_offset;
598 }
599 next_buffer_index_ = -1;
600 }
601
602 // Remove keyframes from |starting_point| onward.
603 keyframe_map_.erase(starting_point_keyframe, keyframe_map_.end());
604
605 // Remove everything from |starting_point| onward.
606 buffers_.erase(starting_point, buffers_.end());
607 }
422 608
423 bool SourceBufferRange::GetNextBuffer( 609 bool SourceBufferRange::GetNextBuffer(
424 scoped_refptr<StreamParserBuffer>* out_buffer) { 610 scoped_refptr<StreamParserBuffer>* out_buffer) {
611 if (waiting_for_keyframe_ ||
612 next_buffer_index_ >= static_cast<int>(buffers_.size())) {
613 return false;
614 }
615
425 DCHECK_GE(next_buffer_index_, 0); 616 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_); 617 *out_buffer = buffers_.at(next_buffer_index_);
430 next_buffer_index_++; 618 next_buffer_index_++;
431 return true; 619 return true;
432 } 620 }
433 621
434 base::TimeDelta SourceBufferRange::GetNextTimestamp() const { 622 base::TimeDelta SourceBufferRange::GetNextTimestamp() const {
435 DCHECK_GE(next_buffer_index_, 0);
436 DCHECK(!buffers_.empty()); 623 DCHECK(!buffers_.empty());
437 624
438 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) 625 if (next_buffer_index_ >= static_cast<int>(buffers_.size()) ||
439 return buffers_.back()->GetEndTimestamp(); 626 next_buffer_index_ < 0 || waiting_for_keyframe_) {
627 return kNoTimestamp();
628 }
440 629
441 return buffers_.at(next_buffer_index_)->GetTimestamp(); 630 return buffers_.at(next_buffer_index_)->GetTimestamp();
442 } 631 }
443 632
444 SourceBufferStream::Timespan 633 SourceBufferStream::Timespan
445 SourceBufferRange::GetBufferedTime() const { 634 SourceBufferRange::GetBufferedTime() const {
446 return std::make_pair(BufferedStart(), BufferedEnd()); 635 return std::make_pair(GetStartTimestamp(), GetEndTimestamp());
447 } 636 }
448 637
449 void SourceBufferRange::AppendToEnd(const SourceBufferRange& range, 638 void SourceBufferRange::AppendToEnd(const SourceBufferRange& range,
450 bool transfer_current_position) { 639 bool transfer_current_position) {
451 DCHECK(CanAppendToEnd(range)); 640 DCHECK(CanAppendToEnd(range));
452 DCHECK(!buffers_.empty()); 641 DCHECK(!buffers_.empty());
453 642
454 if (transfer_current_position) 643 if (transfer_current_position)
455 next_buffer_index_ = range.next_buffer_index_ + buffers_.size(); 644 next_buffer_index_ = range.next_buffer_index_ + buffers_.size();
456 645
457 AppendToEnd(range.buffers_); 646 AppendToEnd(range.buffers_);
458 } 647 }
459 648
460 bool SourceBufferRange::CanAppendToEnd(const SourceBufferRange& range) const { 649 bool SourceBufferRange::CanAppendToEnd(const SourceBufferRange& range) const {
461 return CanAppendToEnd(range.buffers_); 650 return CanAppendToEnd(range.buffers_);
462 } 651 }
463 652
464 bool SourceBufferRange::CanAppendToEnd(const BufferQueue& buffers) const { 653 bool SourceBufferRange::CanAppendToEnd(const BufferQueue& buffers) const {
465 return buffers_.empty() || 654 DCHECK(!buffers_.empty());
466 IsNextInSequence(buffers_.back(), buffers.front()->GetTimestamp()); 655 return IsNextInSequence(buffers_.back(), buffers.front()->GetTimestamp());
467 } 656 }
468 657
469 int SourceBufferRange::BelongsToRange(base::TimeDelta timestamp) const { 658 int SourceBufferRange::BelongsToRange(base::TimeDelta timestamp) const {
470 if (buffers_.empty()) 659 DCHECK(!buffers_.empty());
471 return 1;
472 660
473 if (IsNextInSequence(buffers_.back(), timestamp) || 661 if (IsNextInSequence(buffers_.back(), timestamp) ||
474 (BufferedEnd() >= timestamp && BufferedStart() <= timestamp)) { 662 (GetEndTimestamp() >= timestamp && GetStartTimestamp() <= timestamp)) {
475 return 0; 663 return 0;
476 } 664 }
477 665
478 if (BufferedStart() > timestamp) 666 if (GetStartTimestamp() > timestamp)
479 return -1; 667 return -1;
480 668
481 // |timestamp| must be after this range. 669 // |timestamp| must be after this range.
482 return 1; 670 return 1;
483 } 671 }
484 672
485 bool SourceBufferRange::CanSeekTo(base::TimeDelta timestamp) const { 673 bool SourceBufferRange::CanSeekTo(base::TimeDelta timestamp) const {
486 return !keyframe_map_.empty() && BufferedStart() <= timestamp && 674 return !keyframe_map_.empty() && GetStartTimestamp() <= timestamp &&
487 BufferedEnd() > timestamp; 675 GetEndTimestamp() > timestamp;
488 } 676 }
489 677
490 bool SourceBufferRange::CompletelyOverlaps( 678 bool SourceBufferRange::CompletelyOverlaps(
491 const SourceBufferRange& range) const { 679 const SourceBufferRange& range) const {
492 return BufferedStart() <= range.BufferedStart() && 680 return GetStartTimestamp() <= range.GetStartTimestamp() &&
493 BufferedEnd() >= range.BufferedEnd(); 681 GetEndTimestamp() >= range.GetEndTimestamp();
494 } 682 }
495 683
496 bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const { 684 bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const {
497 return range.BufferedStart() < BufferedEnd() && 685 return range.GetStartTimestamp() < GetEndTimestamp() &&
498 BufferedEnd() < range.BufferedEnd(); 686 GetEndTimestamp() < range.GetEndTimestamp();
499 } 687 }
500 688
501 bool SourceBufferRange::IsStartOverlappedBy(const BufferQueue& buffers) const { 689 base::TimeDelta SourceBufferRange::GetStartTimestamp() const {
502 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp(); 690 DCHECK(!buffers_.empty());
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 {
519 if (buffers_.empty())
520 return kNoTimestamp();
521
522 return buffers_.front()->GetTimestamp(); 691 return buffers_.front()->GetTimestamp();
523 } 692 }
524 693
525 base::TimeDelta SourceBufferRange::BufferedEnd() const { 694 base::TimeDelta SourceBufferRange::GetEndTimestamp() const {
526 if (buffers_.empty()) 695 DCHECK(!buffers_.empty());
527 return kNoTimestamp();
528
529 return buffers_.back()->GetEndTimestamp(); 696 return buffers_.back()->GetEndTimestamp();
530 } 697 }
531 698
532 } // namespace media 699 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698