Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/filters/source_buffer_stream.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <map> | |
| 9 | |
| 10 #include "base/logging.h" | |
| 11 | |
| 12 namespace media { | |
| 13 | |
| 14 // Helper class representing a range of buffered data. All buffers in a | |
| 15 // SourceBufferRange are ordered sequentially in presentation order with no | |
| 16 // gaps. | |
| 17 class SourceBufferRange { | |
| 18 public: | |
| 19 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | |
| 20 | |
| 21 SourceBufferRange(); | |
| 22 | |
| 23 // Adds |new_buffers| into this range. |new_buffers| must belong to this | |
| 24 // range. Garbage collection may occur after Append(). | |
| 25 void Append(const BufferQueue& new_buffers); | |
| 26 | |
| 27 // Updates |next_buffer_index_| to point to the Buffer containing |timestamp|. | |
| 28 // Assumes |timestamp| is valid and in this range. | |
| 29 void Seek(base::TimeDelta timestamp); | |
| 30 | |
| 31 // Updates |out_buffer| with the next buffer in presentation order. Seek() | |
| 32 // must be called before calls to GetNextBuffer(), and buffers are returned | |
| 33 // in order from the last call to Seek(). Returns true if |out_buffer| is | |
| 34 // filled with a valid buffer, false if there is not enough data to fulfill | |
| 35 // the request. | |
| 36 bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer); | |
| 37 | |
| 38 // Returns the Timespan of buffered time in this range. | |
| 39 SourceBufferStream::Timespan GetBufferedTime() const; | |
| 40 | |
| 41 // Appends the buffers from |range| into this range. | |
| 42 // The first buffer in |range| must come directly after the last buffer | |
| 43 // in this range. | |
| 44 // If |transfer_current_position| is true, |range|'s |next_buffer_position_| | |
| 45 // is transfered to this SourceBufferRange. | |
| 46 void AppendRange(const SourceBufferRange& range, | |
| 47 bool transfer_current_position); | |
| 48 bool CanAppendRange(const SourceBufferRange& range) const; | |
| 49 | |
| 50 // Returns whether a buffer with a starting timestamp of |timestamp| would | |
| 51 // belong in this range. This includes a buffer that would be appended to | |
| 52 // the end of the range. | |
| 53 // Returns 0 if |timestamp| is in this range, -1 if |timestamp| appears | |
| 54 // before this range, or 1 if |timestamp| appears after this range. | |
| 55 int BelongsToRange(base::TimeDelta timestamp) const; | |
| 56 | |
| 57 // Returns true if the range has enough data to seek to the specified | |
| 58 // |timestamp|, false otherwise. | |
| 59 bool CanSeekTo(base::TimeDelta timestamp) const; | |
| 60 | |
| 61 // Returns true if the end of this range contains buffers that overlaps with | |
| 62 // the beginning of |range|. | |
| 63 bool EndOverlaps(const SourceBufferRange& range) const; | |
| 64 | |
| 65 private: | |
| 66 // Appends |buffers| to the end of the range and updates |keyframe_map_| as | |
| 67 // it encounters new keyframes. Assumes |buffers| belongs at the end of the | |
| 68 // range. | |
| 69 void AppendToEnd(const BufferQueue& buffers); | |
| 70 | |
| 71 // Returns the start timestamp of the range, or kNoTimestamp if the range is | |
| 72 // empty. | |
| 73 base::TimeDelta BufferedStart() const; | |
| 74 | |
| 75 // Returns the end timestamp of the buffered data. (Note that this is equal to | |
| 76 // the last buffer's timestamp + its duration.) Returns kNoTimestamp if the | |
| 77 // range is empty. | |
| 78 base::TimeDelta BufferedEnd() const; | |
| 79 | |
| 80 // Returns the upper bound for the starting timestamp for the next buffer to | |
| 81 // be appended at the end of the range. Should only be called if |buffers_| is | |
| 82 // nonempty. | |
| 83 base::TimeDelta MaxNextTimestamp() const; | |
| 84 | |
| 85 // An ordered list of buffers in this range. | |
| 86 BufferQueue buffers_; | |
| 87 | |
| 88 // Maps keyframe timestamps to its index position in |buffers_|. | |
| 89 typedef std::map<base::TimeDelta, size_t> KeyframeMap; | |
| 90 KeyframeMap keyframe_map_; | |
| 91 | |
| 92 // Index into |buffers_| for the next buffer to be returned by | |
| 93 // GetBufferedTime(), set to -1 before Seek(). | |
| 94 int next_buffer_index_; | |
| 95 | |
| 96 DISALLOW_COPY_AND_ASSIGN(SourceBufferRange); | |
| 97 }; | |
| 98 | |
| 99 } // namespace media | |
| 100 | |
| 101 // Helper method that returns true if |ranges| is sorted in increasing order, | |
| 102 // false otherwise. | |
| 103 static bool IsRangeListSorted( | |
| 104 const std::list<media::SourceBufferRange*>& ranges) { | |
| 105 base::TimeDelta prev = media::kNoTimestamp(); | |
| 106 for (std::list<media::SourceBufferRange*>::const_iterator itr = | |
| 107 ranges.begin(); itr != ranges.end(); itr++) { | |
| 108 media::SourceBufferStream::Timespan buffered = (*itr)->GetBufferedTime(); | |
| 109 if (prev != media::kNoTimestamp() && prev >= buffered.first) | |
| 110 return false; | |
| 111 prev = buffered.second; | |
| 112 } | |
| 113 return true; | |
| 114 } | |
| 115 | |
| 116 // Comparison function for two Buffers based on timestamp. | |
| 117 static bool BufferComparator(scoped_refptr<media::Buffer> first, | |
| 118 scoped_refptr<media::Buffer> second) { | |
| 119 return first->GetTimestamp() < second->GetTimestamp(); | |
| 120 } | |
| 121 | |
| 122 namespace media { | |
| 123 | |
| 124 SourceBufferStream::SourceBufferStream() | |
| 125 : seek_pending_(false), | |
| 126 seek_buffer_timestamp_(kNoTimestamp()), | |
| 127 selected_range_(NULL) { | |
| 128 } | |
| 129 | |
| 130 SourceBufferStream::~SourceBufferStream() { | |
| 131 while (!ranges_.empty()) { | |
| 132 delete ranges_.front(); | |
| 133 ranges_.pop_front(); | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 bool SourceBufferStream::Append( | |
| 138 const SourceBufferStream::BufferQueue& buffers) { | |
| 139 DCHECK(!buffers.empty()); | |
| 140 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp(); | |
| 141 base::TimeDelta end_timestamp = buffers.back()->GetTimestamp(); | |
| 142 | |
| 143 // Check to see if |buffers| will overlap the currently |selected_range_|, | |
| 144 // and if so, ignore this Append() request. | |
| 145 // TODO(vrk): Support end overlap properly. (crbug.com/125072) | |
| 146 if (selected_range_) { | |
| 147 Timespan selected_range_span = selected_range_->GetBufferedTime(); | |
| 148 if (selected_range_span.second > start_timestamp && | |
| 149 selected_range_span.first <= end_timestamp) { | |
| 150 return false; | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 SourceBufferRange* range = NULL; | |
| 155 RangeList::iterator itr = ranges_.end(); | |
| 156 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) { | |
| 157 int range_value = (*itr)->BelongsToRange(start_timestamp); | |
| 158 | |
| 159 // |start_timestamp| is before the current range in this loop. Because | |
| 160 // |ranges_| is sorted, this means that we need to create a new range and it | |
| 161 // should be placed before |itr|. | |
| 162 if (range_value < 0) | |
| 163 break; | |
| 164 | |
| 165 if (range_value == 0) { | |
| 166 // Found an existing range into which we can append buffers. | |
| 167 range = *itr; | |
| 168 break; | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 if (!range) { | |
| 173 // Ranges must begin with a keyframe. | |
| 174 if (!buffers.front()->IsKeyframe()) | |
| 175 return false; | |
| 176 | |
| 177 range = new SourceBufferRange(); | |
| 178 itr = ranges_.insert(itr, range); | |
| 179 } | |
| 180 | |
| 181 // Append buffers to the appropriate range. | |
| 182 range->Append(buffers); | |
| 183 | |
| 184 // Increment |itr| to be the range after |range|. | |
| 185 itr++; | |
| 186 | |
| 187 // Handle overlaps if they were created. | |
| 188 while (itr != ranges_.end() && range->EndOverlaps(*(*itr))) { | |
|
acolwell GONE FROM CHROMIUM
2012/05/02 00:01:43
nit: You should go back to const Range* here and i
vrk (LEFT CHROMIUM)
2012/05/02 20:34:19
I disagree! I stand by your original comment :) co
| |
| 189 DCHECK_NE(*itr, selected_range_); | |
| 190 delete *itr; | |
| 191 itr = ranges_.erase(itr); | |
| 192 } | |
| 193 | |
| 194 // Merge with neighbor if necessary. | |
| 195 if (itr != ranges_.end() && range->CanAppendRange(*(*itr))) { | |
| 196 bool transfer_current_position = selected_range_ == *itr; | |
| 197 range->AppendRange(*(*itr), transfer_current_position); | |
| 198 // Update |selected_range_| pointer if |range| has become selected after | |
| 199 // merges. | |
| 200 if (transfer_current_position) | |
| 201 selected_range_ = range; | |
| 202 | |
| 203 delete *itr; | |
| 204 ranges_.erase(itr); | |
| 205 } | |
| 206 | |
| 207 // Finally, try to complete pending seek if one exists. | |
| 208 if (seek_pending_) | |
| 209 Seek(seek_buffer_timestamp_); | |
| 210 | |
| 211 DCHECK(IsRangeListSorted(ranges_)); | |
| 212 return true; | |
| 213 } | |
| 214 | |
| 215 void SourceBufferStream::Seek(base::TimeDelta timestamp) { | |
| 216 if (selected_range_) | |
| 217 selected_range_ = NULL; | |
| 218 | |
| 219 seek_buffer_timestamp_ = timestamp; | |
| 220 seek_pending_ = true; | |
| 221 | |
| 222 RangeList::iterator itr = ranges_.end(); | |
| 223 for (itr = ranges_.begin(); itr != ranges_.end(); itr++) { | |
| 224 if ((*itr)->CanSeekTo(timestamp)) | |
| 225 break; | |
| 226 } | |
| 227 | |
| 228 if (itr == ranges_.end()) | |
| 229 return; | |
| 230 | |
| 231 selected_range_ = *itr; | |
| 232 selected_range_->Seek(timestamp); | |
| 233 seek_pending_ = false; | |
| 234 } | |
| 235 | |
| 236 bool SourceBufferStream::GetNextBuffer( | |
| 237 scoped_refptr<StreamParserBuffer>* out_buffer) { | |
| 238 return selected_range_ && selected_range_->GetNextBuffer(out_buffer); | |
| 239 } | |
| 240 | |
| 241 std::list<SourceBufferStream::Timespan> | |
| 242 SourceBufferStream::GetBufferedTime() const { | |
| 243 std::list<Timespan> timespans; | |
| 244 for (RangeList::const_iterator itr = ranges_.begin(); | |
| 245 itr != ranges_.end(); itr++) { | |
| 246 timespans.push_back((*itr)->GetBufferedTime()); | |
| 247 } | |
| 248 return timespans; | |
| 249 } | |
| 250 | |
| 251 SourceBufferRange::SourceBufferRange() | |
| 252 : next_buffer_index_(-1) { | |
| 253 } | |
| 254 | |
| 255 void SourceBufferRange::Append(const BufferQueue& new_buffers) { | |
| 256 base::TimeDelta start_timestamp = new_buffers.front()->GetTimestamp(); | |
| 257 | |
| 258 if (!buffers_.empty() && start_timestamp < BufferedEnd()) { | |
| 259 // We are overwriting existing data, so find the starting point where | |
| 260 // things will get overwritten. | |
| 261 BufferQueue::iterator starting_point = | |
| 262 std::lower_bound(buffers_.begin(), buffers_.end(), | |
| 263 new_buffers.front(), | |
| 264 BufferComparator); | |
| 265 | |
| 266 // Remove everything from |starting_point| onward. | |
| 267 buffers_.erase(starting_point, buffers_.end()); | |
| 268 } | |
| 269 | |
| 270 // Append data. | |
| 271 AppendToEnd(new_buffers); | |
| 272 } | |
| 273 | |
| 274 void SourceBufferRange::AppendToEnd(const BufferQueue& new_buffers) { | |
| 275 for (BufferQueue::const_iterator itr = new_buffers.begin(); | |
| 276 itr != new_buffers.end(); itr++) { | |
| 277 DCHECK((*itr)->GetDuration() > base::TimeDelta()); | |
| 278 DCHECK((*itr)->GetTimestamp() != kNoTimestamp()); | |
| 279 buffers_.push_back(*itr); | |
| 280 if ((*itr)->IsKeyframe()) { | |
| 281 keyframe_map_.insert( | |
| 282 std::make_pair((*itr)->GetTimestamp(), buffers_.size() - 1)); | |
| 283 } | |
| 284 } | |
| 285 } | |
| 286 | |
| 287 void SourceBufferRange::Seek(base::TimeDelta timestamp) { | |
| 288 DCHECK(CanSeekTo(timestamp)); | |
| 289 DCHECK(!keyframe_map_.empty()); | |
| 290 | |
| 291 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp); | |
| 292 // lower_bound() returns the first element >= |timestamp|, so we want the | |
| 293 // previous element if it did not return the element exactly equal to | |
| 294 // |timestamp|. | |
| 295 if (result->first != timestamp) { | |
| 296 DCHECK(result != keyframe_map_.begin()); | |
| 297 result--; | |
| 298 } | |
| 299 next_buffer_index_ = result->second; | |
| 300 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); | |
| 301 } | |
| 302 | |
| 303 bool SourceBufferRange::GetNextBuffer( | |
| 304 scoped_refptr<StreamParserBuffer>* out_buffer) { | |
| 305 DCHECK_GE(next_buffer_index_, 0); | |
| 306 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) | |
| 307 return false; | |
| 308 | |
| 309 *out_buffer = buffers_.at(next_buffer_index_); | |
| 310 next_buffer_index_++; | |
| 311 return true; | |
| 312 } | |
| 313 | |
| 314 SourceBufferStream::Timespan | |
| 315 SourceBufferRange::GetBufferedTime() const { | |
| 316 return std::make_pair(BufferedStart(), BufferedEnd()); | |
| 317 } | |
| 318 | |
| 319 void SourceBufferRange::AppendRange(const SourceBufferRange& range, | |
| 320 bool transfer_current_position) { | |
| 321 DCHECK(CanAppendRange(range)); | |
| 322 DCHECK(!buffers_.empty()); | |
| 323 | |
| 324 if (transfer_current_position) | |
| 325 next_buffer_index_ = range.next_buffer_index_ + buffers_.size(); | |
| 326 | |
| 327 AppendToEnd(range.buffers_); | |
| 328 } | |
| 329 | |
| 330 bool SourceBufferRange::CanAppendRange(const SourceBufferRange& range) const { | |
| 331 | |
|
acolwell GONE FROM CHROMIUM
2012/05/01 23:44:59
nit:remove empty line
vrk (LEFT CHROMIUM)
2012/05/02 20:34:19
Done.
| |
| 332 return range.BufferedStart() >= BufferedEnd() && | |
| 333 range.BufferedStart() <= MaxNextTimestamp(); | |
| 334 } | |
| 335 | |
| 336 int SourceBufferRange::BelongsToRange(base::TimeDelta timestamp) const { | |
| 337 if (buffers_.empty() || MaxNextTimestamp() < timestamp) | |
| 338 return 1; | |
| 339 else if (BufferedStart() > timestamp) | |
| 340 return -1; | |
| 341 else | |
| 342 return 0; | |
| 343 } | |
| 344 | |
| 345 bool SourceBufferRange::CanSeekTo(base::TimeDelta timestamp) const { | |
| 346 return !keyframe_map_.empty() && BufferedStart() <= timestamp && | |
| 347 BufferedEnd() > timestamp; | |
| 348 } | |
| 349 | |
| 350 bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const { | |
| 351 return range.BufferedStart() < BufferedEnd(); | |
| 352 } | |
| 353 | |
| 354 base::TimeDelta SourceBufferRange::BufferedStart() const { | |
| 355 if (buffers_.empty()) | |
| 356 return kNoTimestamp(); | |
| 357 | |
| 358 return buffers_.front()->GetTimestamp(); | |
| 359 } | |
| 360 | |
| 361 base::TimeDelta SourceBufferRange::BufferedEnd() const { | |
| 362 if (buffers_.empty()) | |
| 363 return kNoTimestamp(); | |
| 364 | |
| 365 return buffers_.back()->GetTimestamp() + buffers_.back()->GetDuration(); | |
| 366 } | |
| 367 | |
| 368 base::TimeDelta SourceBufferRange::MaxNextTimestamp() const { | |
| 369 DCHECK(!buffers_.empty()); | |
| 370 | |
| 371 // Because we do not know exactly when is the next timestamp, any buffer | |
| 372 // that starts within 1/3 of the duration past the end of the last buffer | |
| 373 // in the queue is considered the next buffer in this range. | |
| 374 return BufferedEnd() + buffers_.back()->GetDuration() / 3; | |
| 375 } | |
| 376 | |
| 377 } // namespace media | |
| OLD | NEW |