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

Unified Diff: media/filters/source_buffer_stream.cc

Issue 10952034: Remove lingering frames of old data when appending a new segment (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: response to CR Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/source_buffer_stream.cc
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc
index de1a9c943c5c0fb50f42c1dc52ad15721599f429..62c529283ead3693832638dda5e158f8db5dbd17 100644
--- a/media/filters/source_buffer_stream.cc
+++ b/media/filters/source_buffer_stream.cc
@@ -63,15 +63,16 @@ class SourceBufferRange {
// Seeks to the beginning of the range.
void SeekToStart();
- // Finds the next keyframe from |buffers_| after |timestamp|, and creates and
- // returns a new SourceBufferRange with the buffers from that keyframe onward.
+ // Finds the next keyframe from |buffers_| after |timestamp| (or at
+ // |timestamp| if |is_exclusive| is false) 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);
+ SourceBufferRange* SplitRange(base::TimeDelta timestamp, bool is_exclusive);
- // Deletes the buffers from this range whose timestamps are greater than or
- // equal to |buffer|'s timestamp.
+ // Deletes the buffers from this range starting at |timestamp|, exclusive if
+ // |is_exclusive| is true, inclusive otherwise.
// 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.
@@ -81,9 +82,8 @@ class SourceBufferRange {
// may return true even if it does not add any buffers to |deleted_buffers|.
// This indicates that the range had not buffered |next_buffer_index_|, but
// a buffer at that position would have been deleted.
- bool TruncateAt(scoped_refptr<StreamParserBuffer> buffer,
- BufferQueue* deleted_buffers);
- bool TruncateAt(base::TimeDelta timestamp);
+ bool TruncateAt(base::TimeDelta timestamp,
+ BufferQueue* deleted_buffers, bool is_exclusive);
// Deletes all buffers in range.
bool DeleteAll(BufferQueue* deleted_buffers);
@@ -164,6 +164,12 @@ class SourceBufferRange {
// timestamp strictly greater than |timestamp|.
void SeekAhead(base::TimeDelta timestamp, bool skip_given_timestamp);
+ // Returns an iterator in |buffers_| pointing to the buffer at |timestamp|.
+ // If |skip_given_timestamp| is true, this returns the first buffer with
+ // timestamp greater than |timestamp|.
+ BufferQueue::iterator GetBufferItrAt(
+ base::TimeDelta timestamp, bool skip_given_timestamp);
+
// Returns an iterator in |keyframe_map_| pointing to the next keyframe after
// |timestamp|. If |skip_given_timestamp| is true, this returns the first
// keyframe with a timestamp strictly greater than |timestamp|.
@@ -251,6 +257,16 @@ static bool BufferComparator(
return first->GetDecodeTimestamp() < second->GetDecodeTimestamp();
}
+// Returns an estimate of how far from the beginning or end of a range a buffer
+// can be to still be considered in the range, given the |approximate_duration|
+// of a buffer in the stream.
+static base::TimeDelta ComputeFudgeRoom(base::TimeDelta approximate_duration) {
+ // Because we do not know exactly when is the next timestamp, any buffer
+ // that starts within 2x the approximate duration of a buffer is considered
+ // within this range.
+ return 2 * approximate_duration;
+}
+
// An arbitrarily-chosen number to estimate the duration of a buffer if none
// is set and there's not enough information to get a better estimate.
static int kDefaultBufferDurationInMs = 125;
@@ -317,12 +333,20 @@ SourceBufferStream::~SourceBufferStream() {
void SourceBufferStream::OnNewMediaSegment(
base::TimeDelta media_segment_start_time) {
media_segment_start_time_ = media_segment_start_time;
+ new_media_segment_ = true;
- // Find the range that will house the buffers appended through the next
- // Append() call.
+ RangeList::iterator last_range = range_for_next_append_;
range_for_next_append_ = FindExistingRangeFor(media_segment_start_time);
- new_media_segment_ = true;
- last_buffer_timestamp_ = kNoTimestamp();
+
+ // Only reset |last_buffer_timestamp_| if this new media segment is not
+ // adjacent to the previous media segment appended to the stream.
+ if (range_for_next_append_ == ranges_.end() ||
+ !AreAdjacentInSequence(
+ last_buffer_timestamp_, media_segment_start_time)) {
+ last_buffer_timestamp_ = kNoTimestamp();
+ } else {
+ DCHECK(last_range == range_for_next_append_);
+ }
}
bool SourceBufferStream::Append(
@@ -539,46 +563,65 @@ void SourceBufferStream::InsertIntoExistingRange(
SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr;
- // If this is a simple case where we can just append to the end of the range,
- // do so and return.
- if (range_for_new_buffers->CanAppendBuffersToEnd(new_buffers)) {
- range_for_new_buffers->AppendBuffersToEnd(new_buffers);
- return;
+ if (last_buffer_timestamp_ != kNoTimestamp()) {
+ // Clean up the old buffers between the last appended buffer and the
+ // beginning of |new_buffers|.
+ *deleted_next_buffer =
+ DeleteBetween(
+ range_for_new_buffers, last_buffer_timestamp_,
+ new_buffers.front()->GetDecodeTimestamp(), true,
+ deleted_buffers);
+ }
+
+ // If we cannot append the |new_buffers| to the end of the existing range,
+ // this is either a start overlap or an middle overlap. Delete the buffers
+ // that |new_buffers| overlaps.
+ if (!range_for_new_buffers->CanAppendBuffersToEnd(new_buffers)) {
+ *deleted_next_buffer |=
+ DeleteBetween(
+ range_for_new_buffers, new_buffers.front()->GetDecodeTimestamp(),
+ new_buffers.back()->GetDecodeTimestamp(), false,
+ deleted_buffers);
}
- // Otherwise, this is either a start overlap or an middle overlap.
+ range_for_new_buffers->AppendBuffersToEnd(new_buffers);
+}
- // 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.
+bool SourceBufferStream::DeleteBetween(
+ SourceBufferRange* range, base::TimeDelta start_timestamp,
+ base::TimeDelta end_timestamp, bool is_range_exclusive,
+ BufferQueue* deleted_buffers) {
SourceBufferRange* new_next_range =
- range_for_new_buffers->SplitRange(
- new_buffers.back()->GetDecodeTimestamp());
+ range->SplitRange(end_timestamp, is_range_exclusive);
if (new_next_range)
AddToRanges(new_next_range);
- // Delete the buffers that are overlapped by |new_buffers|, then append
- // |new_buffers| to the end of the range.
BufferQueue saved_buffers;
- bool deleted_next_buffer_from_range =
- range_for_new_buffers->TruncateAt(new_buffers.front(), &saved_buffers);
- range_for_new_buffers->AppendBuffersToEnd(new_buffers);
+ bool deleted_next_buffer =
+ range->TruncateAt(start_timestamp, &saved_buffers, is_range_exclusive);
- if (selected_range_ != range_for_new_buffers)
- return;
+ if (selected_range_ != range)
+ return deleted_next_buffer;
- DCHECK(!*deleted_next_buffer);
+ DCHECK(deleted_buffers->empty());
*deleted_buffers = saved_buffers;
- *deleted_next_buffer = deleted_next_buffer_from_range;
- // If this was a middle overlap resulting in a new range, and the next buffer
- // position has been transferred to the newly created range, update the
- // |selected_range_| accordingly.
+ // If the next buffer position has transferred to the split range, set the
+ // selected range accordingly.
if (new_next_range && new_next_range->HasNextBufferPosition()) {
- DCHECK(!range_for_new_buffers->HasNextBufferPosition());
- DCHECK(!*deleted_next_buffer);
+ DCHECK(!range->HasNextBufferPosition());
+ DCHECK(!deleted_next_buffer);
SetSelectedRange(new_next_range);
}
+ return deleted_next_buffer;
+}
+
+bool SourceBufferStream::AreAdjacentInSequence(
+ base::TimeDelta first_timestamp, base::TimeDelta second_timestamp) const {
+ return first_timestamp < second_timestamp &&
+ second_timestamp <=
+ first_timestamp + ComputeFudgeRoom(GetMaxInterbufferDistance());
}
void SourceBufferStream::ResolveCompleteOverlaps(
@@ -627,7 +670,8 @@ void SourceBufferStream::ResolveEndOverlap(
next_range_itr = ranges_.erase(next_range_itr);
SourceBufferRange* new_next_range =
- overlapped_range->SplitRange(range_with_new_buffers->GetEndTimestamp());
+ overlapped_range->SplitRange(
+ range_with_new_buffers->GetEndTimestamp(), true);
// If there were non-overlapped buffers, add the new range to |ranges_|.
if (new_next_range)
@@ -657,9 +701,6 @@ void SourceBufferStream::ResolveEndOverlap(
void SourceBufferStream::UpdateTrackBuffer(const BufferQueue& deleted_buffers) {
DCHECK(!deleted_buffers.empty());
- if (!track_buffer_.empty())
- return;
-
DCHECK(selected_range_);
DCHECK(selected_range_->HasNextBufferPosition());
@@ -769,7 +810,7 @@ void SourceBufferStream::OnSetDuration(base::TimeDelta duration) {
// Need to partially truncate this range.
if ((*itr)->GetStartTimestamp() < duration) {
- bool deleted_seek_point = (*itr)->TruncateAt(duration);
+ bool deleted_seek_point = (*itr)->TruncateAt(duration, NULL, false);
if (deleted_seek_point)
ResetSeekState();
++itr;
@@ -1058,10 +1099,12 @@ void SourceBufferRange::SeekToStart() {
next_buffer_index_ = 0;
}
-SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) {
- // Find the first keyframe after |timestamp|, not including |timestamp|.
+SourceBufferRange* SourceBufferRange::SplitRange(
+ base::TimeDelta timestamp, bool is_exclusive) {
+ // Find the first keyframe after |timestamp|. If |is_exclusive|, do not
+ // include keyframes at |timestamp|.
KeyframeMap::iterator new_beginning_keyframe =
- GetFirstKeyframeAt(timestamp, true);
+ GetFirstKeyframeAt(timestamp, is_exclusive);
// If there is no keyframe after |timestamp|, we can't split the range.
if (new_beginning_keyframe == keyframe_map_.end())
@@ -1096,18 +1139,28 @@ SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) {
return split_range;
}
+SourceBufferRange::BufferQueue::iterator SourceBufferRange::GetBufferItrAt(
+ base::TimeDelta timestamp, bool skip_given_timestamp) {
+ // Need to make a dummy buffer with timestamp |timestamp| in order to search
+ // the |buffers_| container.
+ scoped_refptr<StreamParserBuffer> dummy_buffer =
+ StreamParserBuffer::CopyFrom(NULL, 0, false);
+ dummy_buffer->SetDecodeTimestamp(timestamp);
+
+ if (skip_given_timestamp) {
+ return std::upper_bound(
+ buffers_.begin(), buffers_.end(), dummy_buffer, BufferComparator);
+ }
+ return std::lower_bound(
+ buffers_.begin(), buffers_.end(), dummy_buffer, BufferComparator);
+}
+
SourceBufferRange::KeyframeMap::iterator
SourceBufferRange::GetFirstKeyframeAt(base::TimeDelta timestamp,
bool skip_given_timestamp) {
- KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp);
- // lower_bound() returns the first element >= |timestamp|, so if we don't want
- // to include keyframes == |timestamp|, we have to increment the iterator
- // accordingly.
- if (skip_given_timestamp &&
- result != keyframe_map_.end() && result->first == timestamp) {
- ++result;
- }
- return result;
+ return skip_given_timestamp ?
+ keyframe_map_.upper_bound(timestamp) :
+ keyframe_map_.lower_bound(timestamp);
}
SourceBufferRange::KeyframeMap::iterator
@@ -1127,22 +1180,12 @@ bool SourceBufferRange::DeleteAll(BufferQueue* removed_buffers) {
return TruncateAt(buffers_.begin(), removed_buffers);
}
-bool SourceBufferRange::TruncateAt(base::TimeDelta timestamp) {
- // Need to make a dummy buffer with timestamp |timestamp| in order to search
- // the |buffers_| container.
- scoped_refptr<StreamParserBuffer> dummy_buffer =
- StreamParserBuffer::CopyFrom(NULL, 0, false);
- dummy_buffer->SetDecodeTimestamp(timestamp);
- return TruncateAt(dummy_buffer, NULL);
-}
-
bool SourceBufferRange::TruncateAt(
- scoped_refptr<StreamParserBuffer> buffer, BufferQueue* removed_buffers) {
+ base::TimeDelta timestamp, BufferQueue* removed_buffers,
+ bool is_exclusive) {
// Find the place in |buffers_| where we will begin deleting data.
BufferQueue::iterator starting_point =
- std::lower_bound(buffers_.begin(), buffers_.end(),
- buffer,
- BufferComparator);
+ GetBufferItrAt(timestamp, is_exclusive);
return TruncateAt(starting_point, removed_buffers);
}
@@ -1414,10 +1457,7 @@ bool SourceBufferRange::IsNextInSequence(
}
base::TimeDelta SourceBufferRange::GetFudgeRoom() const {
- // Because we do not know exactly when is the next timestamp, any buffer
- // that starts within 2x the approximate duration of a buffer is considered
- // within this range.
- return 2 * GetApproximateDuration();
+ return ComputeFudgeRoom(GetApproximateDuration());
}
base::TimeDelta SourceBufferRange::GetApproximateDuration() const {
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698