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..7233104290466f3807b58a46d26eeb3a1b7d74e4 100644 |
| --- a/media/filters/source_buffer_stream.cc |
| +++ b/media/filters/source_buffer_stream.cc |
| @@ -18,21 +18,57 @@ 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. |
| + explicit SourceBufferRange(const BufferQueue& new_buffers); |
| - // 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_index_| |
| + // 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 at |next_buffer_index_| was |
| + // deleted, and deletes the |keyframe_map_| entries for the buffers that |
| + // were removed. |
| + // 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 buffer in |deleted_buffers| |
| + // that had been at |next_buffer_index_|. If |next_buffer_index_| did not |
| + // point to any buffer added to |deleted_buffers|, then |next_buffer| points |
| + // to |deleted_buffers.end()|. |
| + void DeleteAfter(scoped_refptr<StreamParserBuffer> buffer, |
| + BufferQueue* deleted_buffers, |
| + BufferQueue::iterator* next_buffer); |
| + // Deletes all buffers in range. |
| + 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 +76,19 @@ 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.) |
| + 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,27 +108,15 @@ 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_|. |
| + 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. |
| - base::TimeDelta BufferedStart() 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 |
| - // range is empty. |
| - base::TimeDelta BufferedEnd() const; |
| + // Returns the start timestamp of the range. |
| + base::TimeDelta GetStartTimestamp() const; |
| // An ordered list of buffers in this range. |
| BufferQueue buffers_; |
| @@ -107,6 +129,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 +158,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 +189,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 +203,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) |
|
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.
|
| 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 +241,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); |
| + |
| + 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); |
| + } |
| +} |
| - selected_range_ = new_range; |
| +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); |
| + UpdateTrackBuffer(range_with_new_buffers_itr, deleted_buffers, |
| + next_buffer); |
| + DCHECK_NE(selected_range_, *next_range_itr); |
| } |
| - 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); |
| + next_range_itr = ranges_.erase(next_range_itr); |
| + |
| + SourceBufferRange* new_next_range = |
| + overlapped_range->SplitRange(range_with_new_buffers->GetEndTimestamp()); |
| + |
| + // 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(); |
| + |
| + // This will update |selected_range_| to no longer point to |
| + // |overlapped_range|. |
| + UpdateTrackBuffer(range_with_new_buffers_itr, deleted_buffers, next_buffer); |
| + DCHECK_NE(selected_range_, overlapped_range.get()); |
| +} |
| + |
| +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()) { |
| + (*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 +456,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 +474,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 +489,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 +504,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,40 +514,125 @@ 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(); |
| } |
| SourceBufferStream::Timespan |
| SourceBufferRange::GetBufferedTime() const { |
| - return std::make_pair(BufferedStart(), BufferedEnd()); |
| + return std::make_pair(GetStartTimestamp(), GetEndTimestamp()); |
| } |
| void SourceBufferRange::AppendToEnd(const SourceBufferRange& range, |
| @@ -462,20 +651,19 @@ bool SourceBufferRange::CanAppendToEnd(const SourceBufferRange& range) const { |
| } |
| bool SourceBufferRange::CanAppendToEnd(const BufferQueue& buffers) const { |
| - return buffers_.empty() || |
| - IsNextInSequence(buffers_.back(), buffers.front()->GetTimestamp()); |
| + DCHECK(!buffers_.empty()); |
| + return IsNextInSequence(buffers_.back(), buffers.front()->GetTimestamp()); |
| } |
| int SourceBufferRange::BelongsToRange(base::TimeDelta timestamp) const { |
| - if (buffers_.empty()) |
| - return 1; |
| + DCHECK(!buffers_.empty()); |
| if (IsNextInSequence(buffers_.back(), timestamp) || |
| - (BufferedEnd() >= timestamp && BufferedStart() <= timestamp)) { |
| + (GetEndTimestamp() >= timestamp && GetStartTimestamp() <= timestamp)) { |
| return 0; |
| } |
| - if (BufferedStart() > timestamp) |
| + if (GetStartTimestamp() > timestamp) |
| return -1; |
| // |timestamp| must be after this range. |
| @@ -483,49 +671,28 @@ int SourceBufferRange::BelongsToRange(base::TimeDelta timestamp) const { |
| } |
| bool SourceBufferRange::CanSeekTo(base::TimeDelta timestamp) const { |
| - return !keyframe_map_.empty() && BufferedStart() <= timestamp && |
| - BufferedEnd() > timestamp; |
| + return !keyframe_map_.empty() && GetStartTimestamp() <= timestamp && |
| + GetEndTimestamp() > timestamp; |
| } |
| bool SourceBufferRange::CompletelyOverlaps( |
| const SourceBufferRange& range) const { |
| - return BufferedStart() <= range.BufferedStart() && |
| - BufferedEnd() >= range.BufferedEnd(); |
| + return GetStartTimestamp() <= range.GetStartTimestamp() && |
| + GetEndTimestamp() >= range.GetEndTimestamp(); |
| } |
| bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const { |
| - return range.BufferedStart() < BufferedEnd() && |
| - 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; |
| + return range.GetStartTimestamp() < GetEndTimestamp() && |
| + GetEndTimestamp() < range.GetEndTimestamp(); |
| } |
| -base::TimeDelta SourceBufferRange::BufferedStart() const { |
| - if (buffers_.empty()) |
| - return kNoTimestamp(); |
| - |
| +base::TimeDelta SourceBufferRange::GetStartTimestamp() const { |
| + DCHECK(!buffers_.empty()); |
| return buffers_.front()->GetTimestamp(); |
| } |
| -base::TimeDelta SourceBufferRange::BufferedEnd() const { |
| - if (buffers_.empty()) |
| - return kNoTimestamp(); |
| - |
| +base::TimeDelta SourceBufferRange::GetEndTimestamp() const { |
| + DCHECK(!buffers_.empty()); |
| return buffers_.back()->GetEndTimestamp(); |
| } |