diff options
author | vrk@google.com <vrk@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-06 18:23:26 +0000 |
---|---|---|
committer | vrk@google.com <vrk@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-06 18:23:26 +0000 |
commit | e54556d60748ec7d73ade8bdb0794ab700a924af (patch) | |
tree | 57def36c70cbd72a953ac078aab54f1e77adec9d /media | |
parent | 20504f4631844c94a49da10bc36744e5091535b3 (diff) | |
download | chromium_src-e54556d60748ec7d73ade8bdb0794ab700a924af.zip chromium_src-e54556d60748ec7d73ade8bdb0794ab700a924af.tar.gz chromium_src-e54556d60748ec7d73ade8bdb0794ab700a924af.tar.bz2 |
Implement start, end, and middle overlaps for SourceBufferStream
Handles cases where the selected range is overlapped.
Does not handle buffer sizes of differing durations.
BUG=126560,125072
TEST=media_unittests
Review URL: https://chromiumcodereview.appspot.com/10389185
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140797 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/filters/source_buffer_stream.cc | 565 | ||||
-rw-r--r-- | media/filters/source_buffer_stream.h | 48 | ||||
-rw-r--r-- | media/filters/source_buffer_stream_unittest.cc | 673 |
3 files changed, 971 insertions, 315 deletions
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc index e12af6b..7000bda 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 @@ -41,21 +77,19 @@ class SourceBufferRange { // the request. bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer); bool HasNextBuffer() const; + + // 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. @@ -75,27 +109,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_; @@ -108,6 +130,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); }; @@ -129,8 +159,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(); } @@ -160,7 +191,6 @@ SourceBufferStream::SourceBufferStream() : seek_pending_(true), seek_buffer_timestamp_(base::TimeDelta()), selected_range_(NULL), - waiting_for_keyframe_(false), end_of_stream_(false) { } @@ -168,7 +198,6 @@ SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config) : seek_pending_(true), seek_buffer_timestamp_(base::TimeDelta()), selected_range_(NULL), - waiting_for_keyframe_(false), end_of_stream_(false) { audio_config_.CopyFrom(audio_config); } @@ -177,7 +206,6 @@ SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config) : seek_pending_(true), seek_buffer_timestamp_(base::TimeDelta()), selected_range_(NULL), - waiting_for_keyframe_(false), end_of_stream_(false) { video_config_.CopyFrom(video_config); } @@ -193,65 +221,38 @@ 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 + // |ranges_| is sorted, this means that we need to create a new range and // 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_) @@ -261,74 +262,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; @@ -388,26 +498,12 @@ bool SourceBufferStream::CanEndOfStream() const { return ranges_.empty() || selected_range_ == ranges_.back(); } -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); } @@ -420,6 +516,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; + } } } } @@ -428,6 +531,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 @@ -440,8 +546,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 @@ -451,21 +556,106 @@ 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; @@ -477,18 +667,19 @@ bool SourceBufferRange::HasNextBuffer() const { } 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, @@ -507,20 +698,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. @@ -528,49 +718,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(); } diff --git a/media/filters/source_buffer_stream.h b/media/filters/source_buffer_stream.h index ed3dfc3..5df241d3 100644 --- a/media/filters/source_buffer_stream.h +++ b/media/filters/source_buffer_stream.h @@ -40,8 +40,6 @@ class MEDIA_EXPORT SourceBufferStream { // of order or overlapping. Assumes all buffers within |buffers| are in // presentation order and are non-overlapping. // Returns true if Append() was successful, false if |buffers| are not added. - // TODO(vrk): Implement proper end-overlapping. (crbug.com/125072) - // This may trigger garbage collection. // TODO(vrk): Implement garbage collection. (crbug.com/125070) bool Append(const BufferQueue& buffers); @@ -84,20 +82,37 @@ class MEDIA_EXPORT SourceBufferStream { private: typedef std::list<SourceBufferRange*> RangeList; + // Appends |new_buffers| into |range_for_new_buffers_itr|, handling start and + // end overlaps if necessary. + void InsertIntoExistingRange( + const RangeList::iterator& range_for_new_buffers_itr, + const BufferQueue& new_buffers); + // Resolve overlapping ranges such that no ranges overlap anymore. - // |range_itr| points to the iterator in |ranges_| immediately after - // |new_range|. Returns the iterator in |ranges_| immediately after - // |new_range|, which may be different from the original |range_itr|. - RangeList::iterator ResolveCompleteOverlaps( - const RangeList::iterator& range_itr, SourceBufferRange* new_range); - RangeList::iterator ResolveEndOverlaps( - const RangeList::iterator& range_itr, SourceBufferRange* new_range); - - // Checks to see if the range pointed to by |range_itr| can be appended to the - // end of |new_range|, and if so, appends the range and updates |ranges_| to - // reflect this. + // |range_with_new_buffers_itr| points to the range that has newly appended + // buffers. + void ResolveCompleteOverlaps( + const RangeList::iterator& range_with_new_buffers_itr); + void ResolveEndOverlap(const RangeList::iterator& range_with_new_buffers_itr); + + // Adds buffers to |track_buffer_| and updates |selected_range_| accordingly. + // |range_with_new_buffers_itr| points to the range containing the newly + // appended buffers. + // |deleted_buffers| contains all the buffers that were deleted as a result + // of appending new buffers into |range_with_new_buffers_itr|. |next_buffer| + // points to the buffer in |deleted_buffers| that should be returned by the + // next call to GetNextBuffer(). Assumes |deleted_buffers| and |next_buffer| + // are valid. + // TODO(vrk): This is a little crazy! Ideas for cleanup in crbug.com/129623. + void UpdateTrackBuffer( + const RangeList::iterator& range_with_new_buffers_itr, + const BufferQueue& deleted_buffers, + const BufferQueue::iterator& next_buffer); + + // Checks to see if |range_with_new_buffers_itr| can be merged with the range + // next to it, and merges them if so. void MergeWithAdjacentRangeIfNecessary( - const RangeList::iterator& range_itr, SourceBufferRange* new_range); + const RangeList::iterator& range_with_new_buffers_itr); // List of disjoint buffered ranges, ordered by start time. RangeList ranges_; @@ -121,11 +136,6 @@ class MEDIA_EXPORT SourceBufferStream { // |track_buffer_| is empty, return buffers from |selected_range_|. BufferQueue track_buffer_; - // True if the next buffer after the end of the |track_buffer_| is not - // buffered yet and we need to wait for the next keyframe after - // |track_buffer_| to be appended. - bool waiting_for_keyframe_; - // True when EndOfStream() has been called and GetNextBuffer() should return // EOS buffers for read requests beyond the buffered data. False initially. bool end_of_stream_; diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc index 7e043d51..07fc967 100644 --- a/media/filters/source_buffer_stream_unittest.cc +++ b/media/filters/source_buffer_stream_unittest.cc @@ -52,6 +52,12 @@ class SourceBufferStreamTest : public testing::Test { start_position * frame_duration_, (end_position + 1) * frame_duration_); } + void CheckExpectedTimespan(int start_position, int end_position) { + SourceBufferStream::TimespanList expected; + expected.push_back(CreateTimespan(start_position, end_position)); + CheckExpectedTimespans(expected); + } + void CheckExpectedTimespans( SourceBufferStream::TimespanList expected_times) { SourceBufferStream::TimespanList actual_times = stream_.GetBufferedTime(); @@ -62,10 +68,10 @@ class SourceBufferStreamTest : public testing::Test { actual_itr != actual_times.end() && expected_itr != expected_times.end(); actual_itr++, expected_itr++) { - EXPECT_EQ(actual_itr->first / frame_duration_, - expected_itr->first / frame_duration_); - EXPECT_EQ(actual_itr->second / frame_duration_, - expected_itr->second / frame_duration_); + EXPECT_EQ(expected_itr->first / frame_duration_, + actual_itr->first / frame_duration_); + EXPECT_EQ(expected_itr->second / frame_duration_, + actual_itr->second / frame_duration_); } } @@ -108,16 +114,21 @@ class SourceBufferStreamTest : public testing::Test { if (expected_data) { const uint8* actual_data = buffer->GetData(); const int actual_size = buffer->GetDataSize(); - EXPECT_EQ(actual_size, expected_size); + EXPECT_EQ(expected_size, actual_size); for (int i = 0; i < std::min(actual_size, expected_size); i++) { - EXPECT_EQ(actual_data[i], expected_data[i]); + EXPECT_EQ(expected_data[i], actual_data[i]); } } EXPECT_EQ(buffer->GetTimestamp() / frame_duration_, current_position); } - EXPECT_EQ(current_position, ending_position + 1); + EXPECT_EQ(ending_position + 1, current_position); + } + + void CheckNoNextBuffer() { + scoped_refptr<StreamParserBuffer> buffer; + EXPECT_FALSE(stream_.GetNextBuffer(&buffer)); } base::TimeDelta frame_duration() const { return frame_duration_; } @@ -158,9 +169,7 @@ TEST_F(SourceBufferStreamTest, Append_SingleRange) { AppendBuffers(0, 15); // Check expected range. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(0, 14)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(0, 14); // Check buffers in range. Seek(0); CheckExpectedBuffers(0, 14); @@ -172,9 +181,7 @@ TEST_F(SourceBufferStreamTest, Append_SingleRange_OneBufferAtATime) { AppendBuffers(i, 1); // Check expected range. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(0, 14)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(0, 14); // Check buffers in range. Seek(0); CheckExpectedBuffers(0, 14); @@ -210,9 +217,7 @@ TEST_F(SourceBufferStreamTest, Append_AdjacentRanges) { AppendBuffers(12, 3); // Check expected range. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(0, 25)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(0, 25); // Check buffers in range. Seek(0); CheckExpectedBuffers(0, 25); @@ -226,21 +231,19 @@ TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe) { AppendBuffers(5, 10); // Check expected range. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(5, 14)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 14); // Check buffers in range. Seek(5); CheckExpectedBuffers(5, 14); // Append fails because the range doesn't begin with a keyframe. AppendBuffers_ExpectFailure(17, 10); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 14); Seek(5); CheckExpectedBuffers(5, 14); } -TEST_F(SourceBufferStreamTest, Overlap_Complete) { +TEST_F(SourceBufferStreamTest, Complete_Overlap) { // Append 5 buffers at positions 5 through 9. AppendBuffers(5, 5); @@ -248,15 +251,13 @@ TEST_F(SourceBufferStreamTest, Overlap_Complete) { AppendBuffers(0, 15); // Check expected range. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(0, 14)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(0, 14); // Check buffers in range. Seek(0); CheckExpectedBuffers(0, 14); } -TEST_F(SourceBufferStreamTest, Overlap_Complete_EdgeCase) { +TEST_F(SourceBufferStreamTest, Complete_Overlap_EdgeCase) { // Make each frame a keyframe so that it's okay to overlap frames at any point // (instead of needing to respect keyframe boundaries). SetStreamInfo(30, 30); @@ -268,15 +269,13 @@ TEST_F(SourceBufferStreamTest, Overlap_Complete_EdgeCase) { AppendBuffers(5, 8); // Check expected range. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(5, 12)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 12); // Check buffers in range. Seek(5); CheckExpectedBuffers(5, 12); } -TEST_F(SourceBufferStreamTest, Overlap_Start) { +TEST_F(SourceBufferStreamTest, Start_Overlap) { // Append 5 buffers at positions 5 through 9. AppendBuffers(5, 5); @@ -284,31 +283,50 @@ TEST_F(SourceBufferStreamTest, Overlap_Start) { AppendBuffers(8, 6); // Check expected range. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(5, 13)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 13); // Check buffers in range. Seek(5); CheckExpectedBuffers(5, 13); } -TEST_F(SourceBufferStreamTest, Overlap_End) { - // Append 6 buffers at positions 10 through 15. - AppendBuffers(10, 6); +TEST_F(SourceBufferStreamTest, End_Overlap) { + // Append 10 buffers at positions 10 through 19. + AppendBuffers(10, 10); + + // Append 10 buffers at positions 5 through 14. + AppendBuffers(5, 10); + + // Check expected range. + CheckExpectedTimespan(5, 19); + // Check buffers in range. + Seek(5); + CheckExpectedBuffers(5, 19); +} + +TEST_F(SourceBufferStreamTest, End_Overlap_Several) { + // Append 10 buffers at positions 10 through 19. + AppendBuffers(10, 10); // Append 8 buffers at positions 5 through 12. AppendBuffers(5, 8); - // Check expected range. + // Check expected ranges: stream should not have kept buffers 13 and 14 + // because the keyframe on which they depended was overwritten. SourceBufferStream::TimespanList expected; expected.push_back(CreateTimespan(5, 12)); + expected.push_back(CreateTimespan(15, 19)); CheckExpectedTimespans(expected); + // Check buffers in range. Seek(5); CheckExpectedBuffers(5, 12); + CheckNoNextBuffer(); + + Seek(19); + CheckExpectedBuffers(15, 19); } -TEST_F(SourceBufferStreamTest, Overlap_Several) { +TEST_F(SourceBufferStreamTest, Complete_Overlap_Several) { // Append 2 buffers at positions 5 through 6. AppendBuffers(5, 2); @@ -337,7 +355,7 @@ TEST_F(SourceBufferStreamTest, Overlap_Several) { CheckExpectedBuffers(0, 19); } -TEST_F(SourceBufferStreamTest, Overlap_SeveralThenMerge) { +TEST_F(SourceBufferStreamTest, Complete_Overlap_Several_Then_Merge) { // Append 2 buffers at positions 5 through 6. AppendBuffers(5, 2); @@ -354,15 +372,13 @@ TEST_F(SourceBufferStreamTest, Overlap_SeveralThenMerge) { AppendBuffers(0, 20); // Check expected ranges. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(0, 21)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(0, 21); // Check buffers in range. Seek(0); CheckExpectedBuffers(0, 21); } -TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete) { +TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected) { // Append 10 buffers at positions 5 through 14. AppendBuffers(5, 10, &kDataA); @@ -373,9 +389,7 @@ TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete) { AppendBuffers(5, 10, &kDataB); // Check timespans are correct. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(5, 14)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 14); // Check that data has been replaced with new data. CheckExpectedBuffers(5, 14, &kDataB); @@ -385,7 +399,7 @@ TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete) { // overlaps the range from which the client is currently grabbing buffers. We // would expect that the SourceBufferStream would return old data until it hits // the keyframe of the new data, after which it will return the new data. -TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete_TrackBuffer) { +TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_TrackBuffer) { // Append 10 buffers at positions 5 through 14. AppendBuffers(5, 10, &kDataA); @@ -396,10 +410,8 @@ TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete_TrackBuffer) { // Do a complete overlap by appending 20 buffers at positions 0 through 19. AppendBuffers(0, 20, &kDataB); - // Check timespans are correct. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(0, 19)); - CheckExpectedTimespans(expected); + // Check timespan is correct. + CheckExpectedTimespan(0, 19); // Expect old data up until next keyframe in new data. CheckExpectedBuffers(6, 9, &kDataA); @@ -413,10 +425,10 @@ TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete_TrackBuffer) { CheckExpectedBuffers(0, 19, &kDataB); // Check timespan continues to be correct. - CheckExpectedTimespans(expected); + CheckExpectedTimespan(0, 19); } -TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete_EdgeCase) { +TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_EdgeCase) { // Append 10 buffers at positions 5 through 14. AppendBuffers(5, 10, &kDataA); @@ -428,9 +440,7 @@ TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete_EdgeCase) { AppendBuffers(5, 10, &kDataB); // Check timespans are correct. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(5, 14)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 14); // Expect old data up until next keyframe in new data. CheckExpectedBuffers(6, 9, &kDataA); @@ -444,10 +454,10 @@ TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete_EdgeCase) { CheckExpectedBuffers(5, 14, &kDataB); // Check timespan continues to be correct. - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 14); } -TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete_Multiple) { +TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_Multiple) { static const uint8 kDataC = 0x55; static const uint8 kDataD = 0x77; @@ -476,14 +486,511 @@ TEST_F(SourceBufferStreamTest, Overlap_Selected_Complete_Multiple) { CheckExpectedBuffers(10, 14, &kDataD); // At this point we cannot fulfill request. - scoped_refptr<StreamParserBuffer> buffer; - EXPECT_FALSE(stream_.GetNextBuffer(&buffer)); + CheckNoNextBuffer(); // Seek back to beginning; all data should be new. Seek(5); CheckExpectedBuffers(5, 14, &kDataD); } +TEST_F(SourceBufferStreamTest, Start_Overlap_Selected) { + // Append 10 buffers at positions 0 through 9. + AppendBuffers(0, 10, &kDataA); + + // Seek to position 5, then add buffers to overlap data at that position. + Seek(5); + AppendBuffers(5, 10, &kDataB); + + // Check expected range. + CheckExpectedTimespan(0, 14); + + // Because we seeked to a keyframe, the next buffers should all be new data. + CheckExpectedBuffers(5, 14, &kDataB); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 4, &kDataA); + CheckExpectedBuffers(5, 14, &kDataB); +} + +TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_TrackBuffer) { + // Append 15 buffers at positions 0 through 14. + AppendBuffers(0, 15, &kDataA); + + // Seek to 10 and get buffer. + Seek(10); + CheckExpectedBuffers(10, 10, &kDataA); + + // Now append 10 buffers of new data at positions 10 through 19. + AppendBuffers(10, 10, &kDataB); + + // Check expected range. + CheckExpectedTimespan(0, 19); + + // The next 4 buffers should be a from the old buffer, followed by a keyframe + // from the new data. + CheckExpectedBuffers(11, 14, &kDataA); + CheckExpectedBuffers(15, 15, &kDataB, true); + + // The rest of the buffers should be new data. + CheckExpectedBuffers(16, 19, &kDataB); + + // Now seek to the beginning; positions 0 through 9 should be the original + // data, positions 10 through 19 should be the new data. + Seek(0); + CheckExpectedBuffers(0, 9, &kDataA); + CheckExpectedBuffers(10, 19, &kDataB); + + // Make sure timespan is still correct. + CheckExpectedTimespan(0, 19); +} + +TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_EdgeCase) { + // Append 10 buffers at positions 5 through 14. + AppendBuffers(5, 10, &kDataA); + + Seek(10); + CheckExpectedBuffers(10, 10, &kDataA); + + // Now replace the last 5 buffers with new data. + AppendBuffers(10, 5, &kDataB); + + // The next 4 buffers should be the origial data, held in the track buffer. + CheckExpectedBuffers(11, 14, &kDataA); + + // The next buffer is at position 15, so we should fail to fulfill the + // request. + CheckNoNextBuffer(); + + // Now append data at 15 through 19 and check to make sure it's correct. + AppendBuffers(15, 5, &kDataB); + CheckExpectedBuffers(15, 19, &kDataB); + + // Seek to beginning of buffered range and check buffers. + Seek(5); + CheckExpectedBuffers(5, 9, &kDataA); + CheckExpectedBuffers(10, 19, &kDataB); + + // Check expected range. + CheckExpectedTimespan(5, 19); +} + +// This test covers the case where new buffers end-overlap an existing, selected +// range, and the next buffer is a keyframe that's being overlapped by new +// buffers. +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : *A*a a a a A a a a a +// new : B b b b b B b b b b +// after: B b b b b*B*b b b b A a a a a +TEST_F(SourceBufferStreamTest, End_Overlap_Selected) { + // Append 10 buffers at positions 5 through 14. + AppendBuffers(5, 10, &kDataA); + + // Seek to position 5. + Seek(5); + + // Now append 10 buffers at positions 0 through 9. + AppendBuffers(0, 10, &kDataB); + + // Check expected range. + CheckExpectedTimespan(0, 14); + + // Because we seeked to a keyframe, the next buffers should be new. + CheckExpectedBuffers(5, 9, &kDataB); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 9, &kDataB); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case where new buffers end-overlap an existing, selected +// range, and the next buffer in the range is after the newly appended buffers. +// In this particular case, the end overlap does not require a split. +// +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : |A a a a a A a a*a*a| +// new : B b b b b B b b b b +// after: |B b b b b B b b b b A a a*a*a| +TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_1) { + // Append 10 buffers at positions 5 through 14. + AppendBuffers(5, 10, &kDataA); + + // Seek to position 10, then move to position 13. + Seek(10); + CheckExpectedBuffers(10, 12, &kDataA); + + // Now append 10 buffers at positions 0 through 9. + AppendBuffers(0, 10, &kDataB); + + // Check expected range. + CheckExpectedTimespan(0, 14); + + // Make sure rest of data is as expected. + CheckExpectedBuffers(13, 14, &kDataA); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 9, &kDataB); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case where new buffers end-overlap an existing, selected +// range, and the next buffer in the range is after the newly appended buffers. +// In this particular case, the end overlap requires a split, and the next +// buffer is in the split range. +// +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : |A a a a a A a a*a*a| +// new : B b b b b B b b +// after: |B b b b b B b b| |A a a*a*a| +TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_2) { + // Append 10 buffers at positions 5 through 14. + AppendBuffers(5, 10, &kDataA); + + // Seek to position 10, then move to position 13. + Seek(10); + CheckExpectedBuffers(10, 12, &kDataA); + + // Now append 8 buffers at positions 0 through 7. + AppendBuffers(0, 8, &kDataB); + + // Check expected ranges. + SourceBufferStream::TimespanList expected; + expected.push_back(CreateTimespan(0, 7)); + expected.push_back(CreateTimespan(10, 14)); + CheckExpectedTimespans(expected); + + // Make sure rest of data is as expected. + CheckExpectedBuffers(13, 14, &kDataA); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 7, &kDataB); + CheckNoNextBuffer(); + + Seek(10); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case where new buffers end-overlap an existing, selected +// range, and the next buffer in the range is after the newly appended buffers. +// In this particular case, the end overlap requires a split, and the next +// buffer was in between the end of the new data and the split range. +// +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : |A a a*a*a A a a a a| +// new : B b b b b B b b +// after: |B b b b b B b b| |A a a a a| +// track: |a a| +TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_3) { + // Append 10 buffers at positions 5 through 14. + AppendBuffers(5, 10, &kDataA); + + // Seek to position 5, then move to position 8. + Seek(5); + CheckExpectedBuffers(5, 7, &kDataA); + + // Now append 8 buffers at positions 0 through 7. + AppendBuffers(0, 8, &kDataB); + + // Check expected ranges. + SourceBufferStream::TimespanList expected; + expected.push_back(CreateTimespan(0, 7)); + expected.push_back(CreateTimespan(10, 14)); + CheckExpectedTimespans(expected); + + // Check for data in the track buffer. + CheckExpectedBuffers(8, 9, &kDataA); + // The buffer immediately after the track buffer should be a keyframe. + CheckExpectedBuffers(10, 10, &kDataA, true); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 7, &kDataB); + Seek(10); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case where new buffers end-overlap an existing, selected +// range, and the next buffer in the range is overlapped by the new buffers. +// In this particular case, the end overlap does not require a split. +// +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : |A a a*a*a A a a a a| +// new : B b b b b B b b b b +// after: |B b b b b B b b b b A a a a a| +// track: |a a| +TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_1) { + // Append 10 buffers at positions 5 through 14. + AppendBuffers(5, 10, &kDataA); + + // Seek to position 5, then move to position 8. + Seek(5); + CheckExpectedBuffers(5, 7, &kDataA); + + // Now append 10 buffers at positions 0 through 9. + AppendBuffers(0, 10, &kDataB); + + // Check expected range. + CheckExpectedTimespan(0, 14); + + // Check for data in the track buffer. + CheckExpectedBuffers(8, 9, &kDataA); + // The buffer immediately after the track buffer should be a keyframe. + CheckExpectedBuffers(10, 10, &kDataA, true); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 9, &kDataB); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case where new buffers end-overlap an existing, selected +// range, and the next buffer in the range is overlapped by the new buffers. +// In this particular case, the end overlap requires a split, and the next +// keyframe after the track buffer is in the split range. +// +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : |A*a*a a a A a a a a| +// new : B b b b b B b +// after: |B b b b b B b| |A a a a a| +// track: |a a a a| +TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_2) { + // Append 10 buffers at positions 5 through 14. + AppendBuffers(5, 10, &kDataA); + + // Seek to position 5, then move to position 6. + Seek(5); + CheckExpectedBuffers(5, 5, &kDataA); + + // Now append 7 buffers at positions 0 through 6. + AppendBuffers(0, 7, &kDataB); + + // Check expected ranges. + SourceBufferStream::TimespanList expected; + expected.push_back(CreateTimespan(0, 6)); + expected.push_back(CreateTimespan(10, 14)); + CheckExpectedTimespans(expected); + + // Check for data in the track buffer. + CheckExpectedBuffers(6, 9, &kDataA); + // The buffer immediately after the track buffer should be a keyframe. + CheckExpectedBuffers(10, 10, &kDataA, true); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 6, &kDataB); + CheckNoNextBuffer(); + + Seek(10); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case where new buffers end-overlap an existing, selected +// range, and the next buffer in the range is overlapped by the new buffers. +// In this particular case, the end overlap requires a split, and the next +// keyframe after the track buffer is in the range with the new buffers. +// +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : |A*a*a a a A a a a a A a a a a| +// new : B b b b b B b b b b B b b +// after: |B b b b b B b b b b B b b| |A a a a a| +// track: |a a a a| +TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_3) { + // Append 15 buffers at positions 5 through 19. + AppendBuffers(5, 15, &kDataA); + + // Seek to position 5, then move to position 6. + Seek(5); + CheckExpectedBuffers(5, 5, &kDataA); + + // Now append 13 buffers at positions 0 through 12. + AppendBuffers(0, 13, &kDataB); + + // Check expected ranges. + SourceBufferStream::TimespanList expected; + expected.push_back(CreateTimespan(0, 12)); + expected.push_back(CreateTimespan(15, 19)); + CheckExpectedTimespans(expected); + + // Check for data in the track buffer. + CheckExpectedBuffers(6, 9, &kDataA); + // The buffer immediately after the track buffer should be a keyframe + // from the new data. + CheckExpectedBuffers(10, 10, &kDataB, true); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 12, &kDataB); + CheckNoNextBuffer(); + + Seek(15); + CheckExpectedBuffers(15, 19, &kDataA); +} + +// This test covers the case where new buffers end-overlap an existing, selected +// range, and there is no keyframe after the end of the new buffers. +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : |A*a*a a a| +// new : B b b b b B +// after: |B b b b b B| +// track: |a a a a| +TEST_F(SourceBufferStreamTest, End_Overlap_Selected_NoKeyframeAfterNew) { + // Append 5 buffers at positions 5 through 9. + AppendBuffers(5, 5, &kDataA); + + // Seek to position 5, then move to position 6. + Seek(5); + CheckExpectedBuffers(5, 5, &kDataA); + + // Now append 6 buffers at positions 0 through 5. + AppendBuffers(0, 6, &kDataB); + + // Check expected range. + CheckExpectedTimespan(0, 5); + + // Check for data in the track buffer. + CheckExpectedBuffers(6, 9, &kDataA); + + // Now there's no data to fulfill the request. + CheckNoNextBuffer(); + + // Let's fill in the gap, buffers 6 through 10. + AppendBuffers(6, 5, &kDataB); + + // We should be able to get the next buffer. + CheckExpectedBuffers(10, 10, &kDataB); +} + +// This test covers the case when new buffers overlap the middle of a selected +// range. This tests the case when there is no split and the next buffer is a +// keyframe. +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : A a a a a*A*a a a a A a a a a +// new : B b b b b +// after: A a a a a*B*b b b b A a a a a +TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_1) { + // Append 15 buffers at positions 0 through 14. + AppendBuffers(0, 15, &kDataA); + + // Seek to position 5. + Seek(5); + + // Now append 5 buffers at positions 5 through 9. + AppendBuffers(5, 5, &kDataB); + + // Check expected range. + CheckExpectedTimespan(0, 14); + + // Check for next data; should be new data. + CheckExpectedBuffers(5, 9, &kDataB); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 4, &kDataA); + CheckExpectedBuffers(5, 9, &kDataB); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case when new buffers overlap the middle of a selected +// range. This tests the case when there is no split and the next buffer is +// after the new buffers. +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : A a a a a A a a a a A*a*a a a +// new : B b b b b +// after: A a a a a B b b b b A*a*a a a +TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_2) { + // Append 15 buffers at positions 0 through 14. + AppendBuffers(0, 15, &kDataA); + + // Seek to 10 then move to position 11. + Seek(10); + CheckExpectedBuffers(10, 10, &kDataA); + + // Now append 5 buffers at positions 5 through 9. + AppendBuffers(5, 5, &kDataB); + + // Check expected range. + CheckExpectedTimespan(0, 14); + + // Make sure data is correct. + CheckExpectedBuffers(11, 14, &kDataA); + Seek(0); + CheckExpectedBuffers(0, 4, &kDataA); + CheckExpectedBuffers(5, 9, &kDataB); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case when new buffers overlap the middle of a selected +// range. This tests the case when there is a split and the next buffer is +// before the new buffers. +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : A a*a*a a A a a a a A a a a a +// new : B b b +// after: A a*a*a a B b b| |A a a a a +TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_3) { + // Append 15 buffers at positions 0 through 14. + AppendBuffers(0, 15, &kDataA); + + // Seek to beginning then move to position 2. + Seek(0); + CheckExpectedBuffers(0, 1, &kDataA); + + // Now append 3 buffers at positions 5 through 7. + AppendBuffers(5, 3, &kDataB); + + // Check expected range. + SourceBufferStream::TimespanList expected; + expected.push_back(CreateTimespan(0, 7)); + expected.push_back(CreateTimespan(10, 14)); + CheckExpectedTimespans(expected); + + // Make sure data is correct. + CheckExpectedBuffers(2, 4, &kDataA); + CheckExpectedBuffers(5, 7, &kDataB); + Seek(10); + CheckExpectedBuffers(10, 14, &kDataA); +} + +// This test covers the case when new buffers overlap the middle of a selected +// range. This tests the case when there is a split and the next buffer is after +// the new buffers but before the split range. +// index: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 +// old : A a a a a A a a*a*a A a a a a +// new : B b b +// after: |A a a a a B b b| |A a a a a| +// track: |a a| +TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_4) { + // Append 15 buffers at positions 0 through 14. + AppendBuffers(0, 15, &kDataA); + + // Seek to 5 then move to position 8. + Seek(5); + CheckExpectedBuffers(5, 7, &kDataA); + + // Now append 3 buffers at positions 5 through 7. + AppendBuffers(5, 3, &kDataB); + + // Check expected range. + SourceBufferStream::TimespanList expected; + expected.push_back(CreateTimespan(0, 7)); + expected.push_back(CreateTimespan(10, 14)); + CheckExpectedTimespans(expected); + + // Buffers 8 and 9 should be in the track buffer. + CheckExpectedBuffers(8, 9, &kDataA); + // The buffer immediately after the track buffer should be a keyframe. + CheckExpectedBuffers(10, 10, &kDataA, true); + + // Make sure all data is correct. + Seek(0); + CheckExpectedBuffers(0, 4, &kDataA); + CheckExpectedBuffers(5, 7, &kDataB); + Seek(10); + CheckExpectedBuffers(10, 14, &kDataA); +} + TEST_F(SourceBufferStreamTest, Seek_Keyframe) { // Append 6 buffers at positions 0 through 5. AppendBuffers(0, 6); @@ -515,8 +1022,7 @@ TEST_F(SourceBufferStreamTest, Seek_NotBuffered) { Seek(0); // Try to get buffer; nothing's appended. - scoped_refptr<StreamParserBuffer> buffer; - EXPECT_FALSE(stream_.GetNextBuffer(&buffer)); + CheckNoNextBuffer(); // Append 2 buffers at positions 0. AppendBuffers(0, 2); @@ -525,7 +1031,7 @@ TEST_F(SourceBufferStreamTest, Seek_NotBuffered) { // Try to get buffer out of range. Seek(2); - EXPECT_FALSE(stream_.GetNextBuffer(&buffer)); + CheckNoNextBuffer(); } TEST_F(SourceBufferStreamTest, Seek_InBetweenTimestamps) { @@ -559,38 +1065,15 @@ TEST_F(SourceBufferStreamTest, Seek_After_TrackBuffer_Filled) { // Do a complete overlap by appending 20 buffers at positions 0 through 19. AppendBuffers(0, 20, &kDataB); - // Check timespans are correct. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(0, 19)); - CheckExpectedTimespans(expected); + // Check timespan is correct. + CheckExpectedTimespan(0, 19); // Seek to beginning; all data should be new. Seek(0); CheckExpectedBuffers(0, 19, &kDataB); // Check timespan continues to be correct. - CheckExpectedTimespans(expected); -} - -// TODO(vrk): When overlaps are handled more elegantly, this test should be -// rewritten to test for more meaningful outcomes. Right now we are just -// testing to make sure nothing crazy happens in this scenario (like losing -// the seek position or garbage collecting the data at position 13). -// Bug for overlaps is crbug.com/125072. -TEST_F(SourceBufferStreamTest, GetNextBuffer_AfterOverlap) { - // Append 15 buffers at positions 0 through 14. - AppendBuffers(0, 15); - - // Seek to buffer at position 13. - Seek(13); - - // Append 5 buffers at positions 10 through 14. - // The current implementation expects a failure, though fixing - // crbug.com/125072 should change this expectation. - AppendBuffers_ExpectFailure(10, 5); - - // Make sure we can still get the buffer at 13. - CheckExpectedBuffers(10, 13); + CheckExpectedTimespan(0, 19); } TEST_F(SourceBufferStreamTest, GetNextBuffer_AfterMerges) { @@ -604,18 +1087,14 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_AfterMerges) { AppendBuffers(5, 5); // Make sure ranges are merged. - SourceBufferStream::TimespanList expected; - expected.push_back(CreateTimespan(5, 14)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 14); // Make sure the next buffer is correct. CheckExpectedBuffers(10, 10); // Append 5 buffers at positions 15 through 19. AppendBuffers(15, 5); - expected.clear(); - expected.push_back(CreateTimespan(5, 19)); - CheckExpectedTimespans(expected); + CheckExpectedTimespan(5, 19); // Make sure the remaining next buffers are correct. CheckExpectedBuffers(11, 14); @@ -630,8 +1109,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenAppend) { CheckExpectedBuffers(0, 3); // Next buffer is at position 4, so should not be able to fulfill request. - scoped_refptr<StreamParserBuffer> buffer; - EXPECT_FALSE(stream_.GetNextBuffer(&buffer)); + CheckNoNextBuffer(); // Append 2 buffers at positions 4 through 5. AppendBuffers(4, 2); @@ -659,8 +1137,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_Overlap_Selected_Complete) { // Next buffer is at position 10, so should not be able to fulfill the // request. - scoped_refptr<StreamParserBuffer> buffer; - EXPECT_FALSE(stream_.GetNextBuffer(&buffer)); + CheckNoNextBuffer(); // Now add 5 new buffers at positions 10 through 14. AppendBuffers(10, 5, &kDataB); |