Chromium Code Reviews| Index: media/filters/source_buffer_stream.cc |
| diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc |
| index 52ce36ca464d2a3c4f4acdcc310acb521ce1f8fb..014b8837875d805b4da9e675b7ee16bcf26c9c8e 100644 |
| --- a/media/filters/source_buffer_stream.cc |
| +++ b/media/filters/source_buffer_stream.cc |
| @@ -18,21 +18,59 @@ class SourceBufferRange { |
| public: |
| typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
| - SourceBufferRange(); |
| + // Creates a source buffer range with |new_buffers|. |new_buffers| cannot be |
| + // empty and the front of |new_buffers| must be a keyframe. |
| + 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.
|
| - // Adds |new_buffers| into this range. |new_buffers| must belong to this |
| - // range. Garbage collection may occur after Append(). |
| - void Append(const BufferQueue& new_buffers); |
| + // Appends |buffers| to the end of the range and updates |keyframe_map_| as |
| + // it encounters new keyframes. Assumes |buffers| belongs at the end of the |
| + // range. |
| + void AppendToEnd(const BufferQueue& buffers); |
| + bool CanAppendToEnd(const BufferQueue& buffers) const; |
| + |
| + // Appends the buffers from |range| into this range. |
| + // The first buffer in |range| must come directly after the last buffer |
| + // in this range. |
| + // 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.
|
| + // is transfered to this SourceBufferRange. |
| + void AppendToEnd(const SourceBufferRange& range, |
| + bool transfer_current_position); |
| + bool CanAppendToEnd(const SourceBufferRange& range) const; |
| // Updates |next_buffer_index_| to point to the Buffer containing |timestamp|. |
| // Assumes |timestamp| is valid and in this range. |
| void Seek(base::TimeDelta timestamp); |
| // Updates |next_buffer_index_| to point to next keyframe after or equal to |
| - // |timestamp|. If there is no such keyframe, then this range will seek to |
| - // the end and return kNoTimestamp(). |
| - // Assumes |timestamp| is valid and in this range. |
| - base::TimeDelta SeekAfter(base::TimeDelta timestamp); |
| + // |timestamp|. |
| + void SeekAfter(base::TimeDelta timestamp); |
| + |
| + // Finds the next keyframe from |buffers_| after |timestamp|, and creates and |
| + // returns a new SourceBufferRange with the buffers from that keyframe onward. |
| + // The buffers in the new SourceBufferRange are moved out of this range. If |
| + // there is no keyframe after |timestamp|, SplitRange() returns null and this |
| + // range is unmodified. |
| + SourceBufferRange* SplitRange(base::TimeDelta timestamp); |
| + |
| + // Deletes the buffers from this range whose timestamps are greater than or |
| + // equal to |buffer|'s timestamp. |
| + // Resets |next_buffer_index_| if the buffer after |next_buffer_index_| was |
| + // deleted. |
| + // If |deleted_buffers| or |next_buffer| are null, they are ignored. |
| + // Otherwise, |deleted_buffers| contains the buffers that were deleted from |
| + // 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
|
| + // |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.
|
| + 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.
|
| + BufferQueue* deleted_buffers, |
| + BufferQueue::iterator* next_buffer); |
| + |
| + // Deletes all buffers in range. |
| + // If |deleted_buffers| or |next_buffer| are null, they are ignored. |
| + // Otherwise, |deleted_buffers| contains the buffers that were deleted from |
| + // this range, and |next_buffer| points to the deleted next buffer or to |
| + // |deleted_buffers.end()| if the next buffer was not deleted. |
| + void DeleteAll(BufferQueue* deleted_buffers, |
| + BufferQueue::iterator* next_buffer); |
| // Updates |out_buffer| with the next buffer in presentation order. Seek() |
| // must be called before calls to GetNextBuffer(), and buffers are returned |
| @@ -40,21 +78,20 @@ class SourceBufferRange { |
| // filled with a valid buffer, false if there is not enough data to fulfill |
| // the request. |
| bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer); |
| + |
| + // Returns the timestamp of the next buffer that will be returned from |
| + // GetNextBuffer(). Returns kNoTimestamp() if Seek() has never been called or |
| + // if this range does not have the next buffer yet. |
| base::TimeDelta GetNextTimestamp() const; |
| + // Returns the end timestamp of the buffered data. (Note that this is equal to |
| + // 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
|
| + // range is empty. |
| + base::TimeDelta GetEndTimestamp() const; |
| + |
| // Returns the Timespan of buffered time in this range. |
| SourceBufferStream::Timespan GetBufferedTime() const; |
| - // Appends the buffers from |range| into this range. |
| - // The first buffer in |range| must come directly after the last buffer |
| - // in this range. |
| - // If |transfer_current_position| is true, |range|'s |next_buffer_position_| |
| - // is transfered to this SourceBufferRange. |
| - void AppendToEnd(const SourceBufferRange& range, |
| - bool transfer_current_position); |
| - bool CanAppendToEnd(const SourceBufferRange& range) const; |
| - bool CanAppendToEnd(const BufferQueue& buffers) const; |
| - |
| // Returns whether a buffer with a starting timestamp of |timestamp| would |
| // belong in this range. This includes a buffer that would be appended to |
| // the end of the range. |
| @@ -74,18 +111,16 @@ class SourceBufferRange { |
| // the beginning of |range|. |
| bool EndOverlaps(const SourceBufferRange& range) const; |
| - // Functions that tell how |buffers| intersects with this range. |
| - // TODO(vrk): These functions should be unnecessary when overlapping the |
| - // selected range is implemented properly. (crbug.com/126560) |
| - bool IsStartOverlappedBy(const BufferQueue& buffers) const; |
| - bool IsEndOverlappedBy(const BufferQueue& buffers) const; |
| - bool IsCompletelyOverlappedBy(const BufferQueue& buffers) const; |
| - |
| private: |
| - // Appends |buffers| to the end of the range and updates |keyframe_map_| as |
| - // it encounters new keyframes. Assumes |buffers| belongs at the end of the |
| - // range. |
| - void AppendToEnd(const BufferQueue& buffers); |
| + // Helper method to delete buffers in |buffers_| starting from |
| + // |starting_point|, an iterator in |buffers_|. |
| + // If |deleted_buffers| or |next_buffer| are null, they are ignored. |
| + // Otherwise, |deleted_buffers| contains the buffers that were deleted from |
| + // this range, and |next_buffer| points to the deleted next buffer or to |
| + // |deleted_buffers.end()| if the next buffer was not deleted. |
| + void DeleteAfter(BufferQueue::iterator starting_point, |
| + BufferQueue* deleted_buffers, |
| + BufferQueue::iterator* next_buffer); |
| // Returns the start timestamp of the range, or kNoTimestamp if the range is |
| // empty. |
| @@ -107,6 +142,14 @@ class SourceBufferRange { |
| // GetBufferedTime(), set to -1 before Seek(). |
| int next_buffer_index_; |
| + // True if the range needs to wait for the next keyframe to be appended before |
| + // returning buffers from GetNextBuffer(). |
| + bool waiting_for_keyframe_; |
| + |
| + // If |waiting_for_keyframe_| is true, this range will wait for the next |
| + // keyframe with timestamp >= |next_keyframe_timestamp_|. |
| + base::TimeDelta next_keyframe_timestamp_; |
| + |
| DISALLOW_COPY_AND_ASSIGN(SourceBufferRange); |
| }; |
| @@ -128,8 +171,9 @@ static bool IsRangeListSorted( |
| } |
| // Comparison function for two Buffers based on timestamp. |
| -static bool BufferComparator(scoped_refptr<media::Buffer> first, |
| - scoped_refptr<media::Buffer> second) { |
| +static bool BufferComparator( |
| + const scoped_refptr<media::StreamParserBuffer>& first, |
| + const scoped_refptr<media::StreamParserBuffer>& second) { |
| return first->GetTimestamp() < second->GetTimestamp(); |
| } |
| @@ -158,8 +202,7 @@ namespace media { |
| SourceBufferStream::SourceBufferStream() |
| : seek_pending_(false), |
| seek_buffer_timestamp_(kNoTimestamp()), |
| - selected_range_(NULL), |
| - waiting_for_keyframe_(false) { |
| + selected_range_(NULL) { |
| } |
| SourceBufferStream::~SourceBufferStream() { |
| @@ -173,65 +216,35 @@ bool SourceBufferStream::Append( |
| const SourceBufferStream::BufferQueue& buffers) { |
| DCHECK(!buffers.empty()); |
| - // Check to see if |buffers| will overlap the currently |selected_range_|, |
| - // and if so, ignore this Append() request. |
| - // TODO(vrk): Support overlapping selected range properly. (crbug.com/126560) |
| - if (selected_range_ && |
| - (selected_range_->IsEndOverlappedBy(buffers) || |
| - selected_range_->IsStartOverlappedBy(buffers))) { |
| - return false; |
| - } |
| - |
| - SourceBufferRange* range = NULL; |
| + RangeList::iterator range_for_new_buffers = ranges_.end(); |
| RangeList::iterator itr = ranges_.end(); |
| base::TimeDelta start_timestamp = buffers.front()->GetTimestamp(); |
| for (itr = ranges_.begin(); itr != ranges_.end(); itr++) { |
| int range_value = (*itr)->BelongsToRange(start_timestamp); |
| - |
| - // |start_timestamp| is before the current range in this loop. Because |
| - // |ranges_| is sorted, this means that we need to create a new range and it |
| - // should be placed before |itr|. |
| - // TODO(vrk): We also break out of the loop if |buffers| completely overlaps |
| - // the current range. This is to cover the case when |buffers| belongs to |
| - // the current range, but also completely overlaps it. This should be |
| - // removed when start overlap is handled properly. |
| - if (range_value < 0 || (*itr)->IsCompletelyOverlappedBy(buffers)) |
| + if (range_value < 0) |
| break; |
| if (range_value == 0) { |
| // Found an existing range into which we can append buffers. |
| - range = *itr; |
| - |
| - if (range->CanAppendToEnd(buffers) && waiting_for_keyframe_) { |
| - // Currently we do not support the case where the next buffer after the |
| - // buffers in the track buffer is not a keyframe. |
| - if (!buffers.front()->IsKeyframe()) |
| - return false; |
| - waiting_for_keyframe_ = false; |
| - } |
| + range_for_new_buffers = itr; |
| break; |
| } |
| } |
| - if (!range) { |
| + if (range_for_new_buffers == ranges_.end()) { |
| // Ranges must begin with a keyframe. |
| if (!buffers.front()->IsKeyframe()) |
| return false; |
| - |
| - range = new SourceBufferRange(); |
| - itr = ranges_.insert(itr, range); |
| + range_for_new_buffers = |
| + ranges_.insert(itr, new SourceBufferRange(buffers)); |
| + } else { |
| + InsertIntoExistingRange(range_for_new_buffers, buffers); |
| } |
| - // Append buffers to the appropriate range. |
| - range->Append(buffers); |
| - |
| - // Increment |itr| to be the range after |range|. |
| - itr++; |
| - |
| // Resolve overlaps. |
| - itr = ResolveCompleteOverlaps(itr, range); |
| - itr = ResolveEndOverlaps(itr, range); |
| - MergeWithAdjacentRangeIfNecessary(itr, range); |
| + ResolveCompleteOverlaps(range_for_new_buffers); |
| + ResolveEndOverlap(range_for_new_buffers); |
| + MergeWithAdjacentRangeIfNecessary(range_for_new_buffers); |
| // Finally, try to complete pending seek if one exists. |
| if (seek_pending_) |
| @@ -241,74 +254,183 @@ bool SourceBufferStream::Append( |
| return true; |
| } |
| -SourceBufferStream::RangeList::iterator |
| -SourceBufferStream::ResolveCompleteOverlaps( |
| - const RangeList::iterator& range_itr, SourceBufferRange* new_range) { |
| - RangeList::iterator itr = range_itr; |
| - while (itr != ranges_.end() && new_range->CompletelyOverlaps(**itr)) { |
| - if (*itr == selected_range_) { |
| - // Get the timestamp for the next buffer in the sequence. |
| - base::TimeDelta next_timestamp = selected_range_->GetNextTimestamp(); |
| - // Then seek to the next keyframe after (or equal to) |next_timestamp|. |
| - // This will allow us to transition from the old buffers to the new |
| - // buffers seamlessly. |
| - base::TimeDelta next_keyframe_timestamp = |
| - new_range->SeekAfter(next_timestamp); |
| - |
| - // If there's no keyframe after |next_timestamp|, then set flag to wait |
| - // for the next keyframe in this range to be appended. |
| - if (next_keyframe_timestamp == kNoTimestamp()) |
| - waiting_for_keyframe_ = true; |
| - |
| - // Add all the old buffers up until |next_keyframe_timestamp| into |
| - // |track_buffer_|. If there was no keyframe, then we add all buffers into |
| - // |track_buffer_|. |
| - scoped_refptr<StreamParserBuffer> next_buffer; |
| - while (selected_range_->GetNextBuffer(&next_buffer) && |
| - (waiting_for_keyframe_ || |
| - next_buffer->GetTimestamp() < next_keyframe_timestamp)) { |
| - track_buffer_.push_back(next_buffer); |
| - } |
| +void SourceBufferStream::InsertIntoExistingRange( |
| + const RangeList::iterator& range_for_new_buffers_itr, |
| + const BufferQueue& new_buffers) { |
| + SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr; |
| + RangeList::iterator next_range_itr = range_for_new_buffers_itr; |
| + next_range_itr++; |
| + |
| + // In case this is a middle overlap, save the buffers that come after the end |
| + // of |new_buffers|, and add them into a new range. |
| + SourceBufferRange* new_portion = |
| + range_for_new_buffers->SplitRange(new_buffers.back()->GetEndTimestamp()); |
| + |
| + if (new_portion) { |
| + next_range_itr = ranges_.insert(next_range_itr, new_portion); |
| + // If |range_for_new_buffers| was selected and the next buffer was in the |
| + // |new_portion| half, update |selected_range_|. |
| + if (selected_range_ == range_for_new_buffers && |
| + new_portion->GetNextTimestamp() != kNoTimestamp()) { |
| + selected_range_ = new_portion; |
| + } |
| + } |
| + |
| + BufferQueue deleted_buffers; |
| + BufferQueue::iterator next_buffer; |
| + range_for_new_buffers->DeleteAfter( |
| + new_buffers.front(), &deleted_buffers, &next_buffer); |
| + range_for_new_buffers->AppendToEnd(new_buffers); |
| - selected_range_ = new_range; |
| + if (selected_range_ == range_for_new_buffers && |
| + !deleted_buffers.empty() && next_buffer != deleted_buffers.end()) { |
| + UpdateTrackBuffer(range_for_new_buffers_itr, deleted_buffers, next_buffer); |
| + } |
| +} |
| + |
| +void SourceBufferStream::ResolveCompleteOverlaps( |
| + const RangeList::iterator& range_with_new_buffers_itr) { |
| + SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr; |
| + RangeList::iterator next_range_itr = range_with_new_buffers_itr; |
| + next_range_itr++; |
| + |
| + while (next_range_itr != ranges_.end() && |
| + range_with_new_buffers->CompletelyOverlaps(**next_range_itr)) { |
| + if (*next_range_itr == selected_range_) { |
| + // Delete everything from the selected range that |new_range| overlaps, |
| + // and save the next buffers. |
| + BufferQueue deleted_buffers; |
| + BufferQueue::iterator next_buffer; |
| + (*next_range_itr)->DeleteAll(&deleted_buffers, &next_buffer); |
| + |
| + // Update |selected_range_| then update the track buffer. |
| + 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
|
| + UpdateTrackBuffer(range_with_new_buffers_itr, |
| + deleted_buffers, next_buffer); |
| } |
| - delete *itr; |
| - itr = ranges_.erase(itr); |
| + delete *next_range_itr; |
| + next_range_itr = ranges_.erase(next_range_itr); |
| } |
| - return itr; |
| } |
| -SourceBufferStream::RangeList::iterator |
| -SourceBufferStream::ResolveEndOverlaps( |
| - const RangeList::iterator& range_itr, SourceBufferRange* new_range) { |
| - RangeList::iterator itr = range_itr; |
| - while (itr != ranges_.end() && new_range->EndOverlaps(**itr)) { |
| - DCHECK_NE(*itr, selected_range_); |
| - delete *itr; |
| - itr = ranges_.erase(itr); |
| +void SourceBufferStream::ResolveEndOverlap( |
| + const RangeList::iterator& range_with_new_buffers_itr) { |
| + SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr; |
| + RangeList::iterator next_range_itr = range_with_new_buffers_itr; |
| + next_range_itr++; |
| + |
| + if (next_range_itr == ranges_.end() || |
| + !range_with_new_buffers->EndOverlaps(**next_range_itr)) { |
| + return; |
| + } |
| + |
| + // Split the overlapped range after |range_with_new_buffers|'s last buffer |
| + // overlaps. Now |overlapped_range| contains only the buffers that do not |
| + // belong in |ranges_| anymore, and |new_next_range| contains buffers that |
| + // go after |range_with_new_buffers| (without overlap). |
| + scoped_ptr<SourceBufferRange> overlapped_range(*next_range_itr); |
| + SourceBufferRange* new_next_range = |
| + overlapped_range->SplitRange(range_with_new_buffers->GetEndTimestamp()); |
| + |
| + // Remove |overlapped_range| from the range list, since it now contains only |
| + // buffers that are redundant with |range_with_new_buffers|. |
| + 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.
|
| + |
| + // If there were non-overlapped buffers, add the new range to |ranges_|. |
| + if (new_next_range) |
| + ranges_.insert(next_range_itr, new_next_range); |
| + |
| + // If we didn't overlap a selected range, return. |
| + if (selected_range_ != overlapped_range.get()) |
| + return; |
| + |
| + // If the next buffer was in the |new_next_range| half of the overlapped |
| + // range, then the |selected_range_| is now |new_next_range|. |
| + if (new_next_range && |
| + new_next_range->GetNextTimestamp() != kNoTimestamp()) { |
| + selected_range_ = new_next_range; |
| + return; |
| + } |
| + |
| + // Otherwise, update track buffer with overlapped buffers. |
| + BufferQueue deleted_buffers; |
| + scoped_refptr<StreamParserBuffer> buffer; |
| + while (overlapped_range->GetNextBuffer(&buffer)) { |
| + deleted_buffers.push_back(buffer); |
| + } |
| + BufferQueue::iterator next_buffer = deleted_buffers.begin(); |
| + 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.
|
| +} |
| + |
| +void SourceBufferStream::UpdateTrackBuffer( |
| + const RangeList::iterator& range_with_new_buffers_itr, |
| + const BufferQueue& deleted_buffers, |
| + const BufferQueue::iterator& next_buffer) { |
| + DCHECK(!deleted_buffers.empty() && next_buffer != deleted_buffers.end()); |
| + |
| + SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr; |
| + |
| + // Seek to the next keyframe after (or equal to) the timestamp of the next |
| + // buffer being overlapped. |
| + range_with_new_buffers->SeekAfter((*next_buffer)->GetTimestamp()); |
| + selected_range_ = range_with_new_buffers; |
| + |
| + base::TimeDelta next_keyframe_timestamp = |
| + range_with_new_buffers->GetNextTimestamp(); |
| + |
| + if (track_buffer_.empty()) { |
| + // Add all the old buffers up until |next_keyframe_timestamp| into |
| + // |track_buffer_|. If there was no next keyframe, then we add all buffers |
| + // into |track_buffer_|. |
| + BufferQueue::iterator next_buffer_itr = next_buffer; |
| + while (next_buffer_itr != deleted_buffers.end() && |
| + (next_keyframe_timestamp == kNoTimestamp() || |
| + (*next_buffer_itr)->GetTimestamp() < next_keyframe_timestamp)) { |
| + track_buffer_.push_back(*next_buffer_itr); |
| + next_buffer_itr++; |
| + } |
| + } |
| + |
| + // See if the next range contains the keyframe after the end of the |
| + // |track_buffer_|, and if so, change |selected_range_|. |
| + if (next_keyframe_timestamp == kNoTimestamp()) { |
| + DCHECK(!track_buffer_.empty()); |
| + RangeList::iterator next_range_itr = range_with_new_buffers_itr; |
| + next_range_itr++; |
| + 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
|
| + (*next_range_itr)->SeekAfter(track_buffer_.back()->GetEndTimestamp()); |
| + if (IsNextInSequence(track_buffer_.back(), |
| + (*next_range_itr)->GetNextTimestamp())) { |
| + selected_range_ = *next_range_itr; |
| + } |
| + } |
| } |
| - return itr; |
| } |
| void SourceBufferStream::MergeWithAdjacentRangeIfNecessary( |
| - const RangeList::iterator& itr, SourceBufferRange* new_range) { |
| - if (itr != ranges_.end() && new_range->CanAppendToEnd(**itr)) { |
| - bool transfer_current_position = selected_range_ == *itr; |
| - new_range->AppendToEnd(**itr, transfer_current_position); |
| + const RangeList::iterator& range_with_new_buffers_itr) { |
| + SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr; |
| + RangeList::iterator next_range_itr = range_with_new_buffers_itr; |
| + next_range_itr++; |
| + |
| + if (next_range_itr != ranges_.end() && |
| + range_with_new_buffers->CanAppendToEnd(**next_range_itr)) { |
| + bool transfer_current_position = selected_range_ == *next_range_itr; |
| + range_with_new_buffers->AppendToEnd(**next_range_itr, |
| + transfer_current_position); |
| // Update |selected_range_| pointer if |range| has become selected after |
| // merges. |
| if (transfer_current_position) |
| - selected_range_ = new_range; |
| + selected_range_ = range_with_new_buffers; |
| - delete *itr; |
| - ranges_.erase(itr); |
| + delete *next_range_itr; |
| + ranges_.erase(next_range_itr); |
| } |
| } |
| void SourceBufferStream::Seek(base::TimeDelta timestamp) { |
| selected_range_ = NULL; |
| track_buffer_.clear(); |
| - waiting_for_keyframe_ = false; |
| seek_buffer_timestamp_ = timestamp; |
| seek_pending_ = true; |
| @@ -347,26 +469,12 @@ SourceBufferStream::GetBufferedTime() const { |
| return timespans; |
| } |
| -SourceBufferRange::SourceBufferRange() |
| - : next_buffer_index_(-1) { |
| -} |
| - |
| -void SourceBufferRange::Append(const BufferQueue& new_buffers) { |
| - base::TimeDelta start_timestamp = new_buffers.front()->GetTimestamp(); |
| - |
| - if (!buffers_.empty() && start_timestamp < BufferedEnd()) { |
| - // We are overwriting existing data, so find the starting point where |
| - // things will get overwritten. |
| - BufferQueue::iterator starting_point = |
| - std::lower_bound(buffers_.begin(), buffers_.end(), |
| - new_buffers.front(), |
| - BufferComparator); |
| - |
| - // Remove everything from |starting_point| onward. |
| - buffers_.erase(starting_point, buffers_.end()); |
| - } |
| - |
| - // Append data. |
| +SourceBufferRange::SourceBufferRange(const BufferQueue& new_buffers) |
| + : next_buffer_index_(-1), |
| + waiting_for_keyframe_(false), |
| + next_keyframe_timestamp_(kNoTimestamp()) { |
| + DCHECK(!new_buffers.empty()); |
| + DCHECK(new_buffers.front()->IsKeyframe()); |
| AppendToEnd(new_buffers); |
| } |
| @@ -379,6 +487,13 @@ void SourceBufferRange::AppendToEnd(const BufferQueue& new_buffers) { |
| if ((*itr)->IsKeyframe()) { |
| keyframe_map_.insert( |
| std::make_pair((*itr)->GetTimestamp(), buffers_.size() - 1)); |
| + |
| + if (waiting_for_keyframe_ && |
| + (*itr)->GetTimestamp() >= next_keyframe_timestamp_) { |
| + next_buffer_index_ = buffers_.size() - 1; |
| + next_keyframe_timestamp_ = base::TimeDelta(); |
| + waiting_for_keyframe_ = false; |
| + } |
| } |
| } |
| } |
| @@ -387,6 +502,9 @@ void SourceBufferRange::Seek(base::TimeDelta timestamp) { |
| DCHECK(CanSeekTo(timestamp)); |
| DCHECK(!keyframe_map_.empty()); |
| + next_keyframe_timestamp_ = base::TimeDelta(); |
| + waiting_for_keyframe_ = false; |
| + |
| KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp); |
| // lower_bound() returns the first element >= |timestamp|, so we want the |
| // previous element if it did not return the element exactly equal to |
| @@ -399,8 +517,7 @@ void SourceBufferRange::Seek(base::TimeDelta timestamp) { |
| DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); |
| } |
| -base::TimeDelta SourceBufferRange::SeekAfter(base::TimeDelta timestamp) { |
| - DCHECK_EQ(BelongsToRange(timestamp), 0); |
| +void SourceBufferRange::SeekAfter(base::TimeDelta timestamp) { |
| DCHECK(!keyframe_map_.empty()); |
| // lower_bound() returns the first element >= |timestamp|, so |result| is the |
| @@ -410,37 +527,126 @@ base::TimeDelta SourceBufferRange::SeekAfter(base::TimeDelta timestamp) { |
| // If there isn't a keyframe after |timestamp|, then seek to end and return |
| // kNoTimestamp to signal such. |
| if (result == keyframe_map_.end()) { |
| - next_buffer_index_ = buffers_.size(); |
| - return kNoTimestamp(); |
| + waiting_for_keyframe_ = true; |
| + next_buffer_index_ = -1; |
| + next_keyframe_timestamp_ = timestamp; |
| + return; |
| } |
| next_buffer_index_ = result->second; |
| DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); |
| - return result->first; |
| } |
| +SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) { |
| + // Find the first keyframe after |timestamp|. |
| + KeyframeMap::iterator new_beginning_keyframe = |
| + keyframe_map_.lower_bound(timestamp); |
| + |
| + // If there is no keyframe after |timestamp|, we can't split the range. |
| + if (new_beginning_keyframe == keyframe_map_.end()) |
| + return NULL; |
| + |
| + int keyframe_index = new_beginning_keyframe->second; |
| + DCHECK_LT(keyframe_index, static_cast<int>(buffers_.size())); |
| + |
| + BufferQueue removed_buffers; |
| + BufferQueue::iterator next_buffer; |
| + DeleteAfter( |
| + buffers_.begin() + keyframe_index, &removed_buffers, &next_buffer); |
| + |
| + SourceBufferRange* split_range = new SourceBufferRange(removed_buffers); |
| + if (next_buffer != removed_buffers.end()) { |
| + split_range->next_buffer_index_ = next_buffer - removed_buffers.begin(); |
| + } |
| + return split_range; |
| +} |
| + |
| +void SourceBufferRange::DeleteAll(BufferQueue* removed_buffers, |
| + BufferQueue::iterator* next_buffer) { |
| + DeleteAfter(buffers_.begin(), removed_buffers, next_buffer); |
| +} |
| + |
| +void SourceBufferRange::DeleteAfter( |
| + scoped_refptr<StreamParserBuffer> buffer, |
| + BufferQueue* removed_buffers, |
| + BufferQueue::iterator* next_buffer) { |
| + // Find the place in |buffers_| where we will begin deleting data. |
| + BufferQueue::iterator starting_point = |
| + std::lower_bound(buffers_.begin(), buffers_.end(), |
| + buffer, |
| + BufferComparator); |
| + DeleteAfter(starting_point, removed_buffers, next_buffer); |
| +} |
| + |
| +void SourceBufferRange::DeleteAfter( |
| + BufferQueue::iterator starting_point, |
| + BufferQueue* removed_buffers, |
| + BufferQueue::iterator* next_buffer) { |
| + // Return if we're not deleting anything. |
| + if (starting_point == buffers_.end()) |
| + return; |
| + |
| + // Find the first keyframe after |starting_point|. |
| + KeyframeMap::iterator starting_point_keyframe = |
| + keyframe_map_.lower_bound((*starting_point)->GetTimestamp()); |
| + |
| + // Save the buffers we're about to delete. |
| + if (removed_buffers) { |
| + BufferQueue saved(starting_point, buffers_.end()); |
| + removed_buffers->swap(saved); |
| + if (next_buffer) |
| + *next_buffer = removed_buffers->end(); |
| + } |
| + |
| + // Reset the next buffer index if we will be deleting the buffer that's next |
| + // in sequence. |
| + base::TimeDelta next_buffer_timestamp = GetNextTimestamp(); |
| + if (next_buffer_timestamp != kNoTimestamp() && |
| + next_buffer_timestamp >= (*starting_point)->GetTimestamp()) { |
| + if (removed_buffers && next_buffer) { |
| + int starting_offset = starting_point - buffers_.begin(); |
| + int next_buffer_offset = next_buffer_index_ - starting_offset; |
| + DCHECK_GE(next_buffer_offset, 0); |
| + *next_buffer = removed_buffers->begin() + next_buffer_offset; |
| + } |
| + next_buffer_index_ = -1; |
| + } |
| + |
| + // Remove keyframes from |starting_point| onward. |
| + keyframe_map_.erase(starting_point_keyframe, keyframe_map_.end()); |
| + |
| + // Remove everything from |starting_point| onward. |
| + buffers_.erase(starting_point, buffers_.end()); |
| +} |
| bool SourceBufferRange::GetNextBuffer( |
| scoped_refptr<StreamParserBuffer>* out_buffer) { |
| - DCHECK_GE(next_buffer_index_, 0); |
| - if (next_buffer_index_ >= static_cast<int>(buffers_.size())) |
| + if (waiting_for_keyframe_ || |
| + next_buffer_index_ >= static_cast<int>(buffers_.size())) { |
| return false; |
| + } |
| + DCHECK_GE(next_buffer_index_, 0); |
| *out_buffer = buffers_.at(next_buffer_index_); |
| next_buffer_index_++; |
| return true; |
| } |
| base::TimeDelta SourceBufferRange::GetNextTimestamp() const { |
| - DCHECK_GE(next_buffer_index_, 0); |
| DCHECK(!buffers_.empty()); |
| - if (next_buffer_index_ >= static_cast<int>(buffers_.size())) |
| - return buffers_.back()->GetEndTimestamp(); |
| + if (next_buffer_index_ >= static_cast<int>(buffers_.size()) || |
| + next_buffer_index_ < 0 || waiting_for_keyframe_) { |
| + return kNoTimestamp(); |
| + } |
| return buffers_.at(next_buffer_index_)->GetTimestamp(); |
| } |
| +base::TimeDelta SourceBufferRange::GetEndTimestamp() const { |
| + 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.
|
| +} |
| + |
| SourceBufferStream::Timespan |
| SourceBufferRange::GetBufferedTime() const { |
| return std::make_pair(BufferedStart(), BufferedEnd()); |
| @@ -498,34 +704,15 @@ bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const { |
| BufferedEnd() < range.BufferedEnd(); |
| } |
| -bool SourceBufferRange::IsStartOverlappedBy(const BufferQueue& buffers) const { |
| - base::TimeDelta start_timestamp = buffers.front()->GetTimestamp(); |
| - return BufferedStart() < start_timestamp && start_timestamp < BufferedEnd(); |
| -} |
| - |
| -bool SourceBufferRange::IsEndOverlappedBy(const BufferQueue& buffers) const { |
| - base::TimeDelta end_timestamp = buffers.back()->GetEndTimestamp(); |
| - return BufferedStart() < end_timestamp && end_timestamp < BufferedEnd(); |
| -} |
| - |
| -bool SourceBufferRange::IsCompletelyOverlappedBy( |
| - const BufferQueue& buffers) const { |
| - base::TimeDelta start_timestamp = buffers.front()->GetTimestamp(); |
| - base::TimeDelta end_timestamp = buffers.back()->GetEndTimestamp(); |
| - return start_timestamp <= BufferedStart() && BufferedEnd() <= end_timestamp; |
| -} |
| - |
| base::TimeDelta SourceBufferRange::BufferedStart() const { |
| if (buffers_.empty()) |
| return kNoTimestamp(); |
| - |
| return buffers_.front()->GetTimestamp(); |
| } |
| base::TimeDelta SourceBufferRange::BufferedEnd() const { |
| if (buffers_.empty()) |
| return kNoTimestamp(); |
| - |
| return buffers_.back()->GetEndTimestamp(); |
| } |