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

Unified Diff: media/filters/source_buffer_stream.cc

Issue 10692053: Remove buffer duration calculation from WebMClusterParser and update SourceBufferStream accordingly (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase ToT Created 8 years, 6 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
Index: media/filters/source_buffer_stream.cc
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc
index 2f2000970fdac573fecbc22689782630bab96b7d..372bb1b77d8efc32e92950988ccf0d100056f730 100644
--- a/media/filters/source_buffer_stream.cc
+++ b/media/filters/source_buffer_stream.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include <map>
+#include "base/bind.h"
#include "base/logging.h"
namespace media {
@@ -18,12 +19,15 @@ class SourceBufferRange {
public:
typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
+ typedef base::Callback<base::TimeDelta()> InterbufferDistanceCB;
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 nit: Add comment about what this callback's return
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 Done.
+
// Creates a source buffer range with |new_buffers|. |new_buffers| cannot be
// empty and the front of |new_buffers| must be a keyframe.
// |media_segment_start_time| refers to the starting timestamp for the media
// segment to which these buffers belong.
SourceBufferRange(const BufferQueue& new_buffers,
- base::TimeDelta media_segment_start_time);
+ base::TimeDelta media_segment_start_time,
+ const InterbufferDistanceCB& interbuffer_distance_cb);
// 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
@@ -46,7 +50,11 @@ class SourceBufferRange {
// Updates |next_buffer_index_| to point to next keyframe after or equal to
// |timestamp|.
- void SeekAfter(base::TimeDelta timestamp);
+ void SeekAheadTo(base::TimeDelta timestamp);
+
+ // Updates |next_buffer_index_| to point to next keyframe strictly after
+ // |timestamp|.
+ void SeekAheadPast(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.
@@ -62,12 +70,14 @@ class SourceBufferRange {
// were removed.
// |deleted_buffers| contains the buffers that were deleted from this range,
// starting at the buffer that had been at |next_buffer_index_|.
- // |deleted_buffers| is empty if the buffer at |next_buffer_index_| was not
- // deleted.
- void DeleteAfter(scoped_refptr<StreamParserBuffer> buffer,
- BufferQueue* deleted_buffers);
+ // Returns true if the |next_buffer_index_| is reset. Note that this method
+ // 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);
// Deletes all buffers in range.
- void DeleteAll(BufferQueue* deleted_buffers);
+ bool DeleteAll(BufferQueue* deleted_buffers);
// Updates |out_buffer| with the next buffer in presentation order. Seek()
// must be called before calls to GetNextBuffer(), and buffers are returned
@@ -83,17 +93,20 @@ class SourceBufferRange {
bool HasNextBufferPosition() const;
// Returns the timestamp of the next buffer that will be returned from
- // GetNextBuffer(). This may be an approximation if the range does not have
- // next buffer buffered.
+ // GetNextBuffer(), or kNoTimestamp() if the timestamp is unknown.
base::TimeDelta GetNextTimestamp() const;
// Returns the start timestamp of the range.
base::TimeDelta GetStartTimestamp() const;
- // Returns the end timestamp of the buffered data. (Note that this is equal to
- // the last buffer's timestamp + its duration.)
+ // Returns the timestamp of the last buffer in the range.
base::TimeDelta GetEndTimestamp() const;
+ // Returns the timestamp for the end of the buffered region in this range.
+ // This is an approximation if the duration for the last buffer in the range
+ // is unset.
+ base::TimeDelta GetBufferedEndTimestamp() 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.
@@ -111,17 +124,38 @@ class SourceBufferRange {
// the beginning of |range|.
bool EndOverlaps(const SourceBufferRange& range) const;
+ // Returns true if |timestamp| is the timestamp of the next buffer in
+ // sequence after |buffer|, false otherwise.
+ bool IsNextInSequence(
+ const scoped_refptr<media::StreamParserBuffer>& buffer,
+ base::TimeDelta timestamp) const;
+
private:
- // Helper method to delete buffers in |buffers_| starting from
+ typedef std::map<base::TimeDelta, size_t> KeyframeMap;
+
+ // Seeks the range to the next keyframe after |timestamp|. If
+ // |skip_given_timestamp| is true, the seek will go to a keyframe with a
+ // timestamp strictly greater than |timestamp|.
+ void SeekAhead(base::TimeDelta timestamp, bool skip_given_timestamp);
+ KeyframeMap::iterator GetFirstKeyframeAfter(
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 nit: Remove After since this would be more of an A
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 Good call on both accounts, done.
+ base::TimeDelta timestamp, bool skip_given_timestamp);
+
+ // Helper method to delete buffers in |buffers_| starting at
// |starting_point|, an iterator in |buffers_|.
- void DeleteAfter(const BufferQueue::iterator& starting_point,
- BufferQueue* deleted_buffers);
+ bool TruncateAt(const BufferQueue::iterator& starting_point,
+ BufferQueue* deleted_buffers);
+
+ // Returns the distance in time estimating how far from the beginning or end
+ // of this range a buffer can be to considered in the range.
+ base::TimeDelta GetFudgeRoom() const;
+
+ // Returns the approximate duration of a buffer in this range.
+ base::TimeDelta GetApproximateDuration() const;
// An ordered list of buffers in this range.
BufferQueue buffers_;
// Maps keyframe timestamps to its index position in |buffers_|.
- typedef std::map<base::TimeDelta, size_t> KeyframeMap;
KeyframeMap keyframe_map_;
// Index into |buffers_| for the next buffer to be returned by
@@ -146,6 +180,9 @@ class SourceBufferRange {
// range).
base::TimeDelta media_segment_start_time_;
+ // Called to get the largest interbuffer distance seen so far in the stream.
+ InterbufferDistanceCB interbuffer_distance_cb_;
+
DISALLOW_COPY_AND_ASSIGN(SourceBufferRange);
};
@@ -157,7 +194,7 @@ static bool IsRangeListSorted(
const std::list<media::SourceBufferRange*>& ranges) {
base::TimeDelta prev = media::kNoTimestamp();
for (std::list<media::SourceBufferRange*>::const_iterator itr =
- ranges.begin(); itr != ranges.end(); itr++) {
+ ranges.begin(); itr != ranges.end(); ++itr) {
if (prev != media::kNoTimestamp() && prev >= (*itr)->GetStartTimestamp())
return false;
prev = (*itr)->GetEndTimestamp();
@@ -172,48 +209,35 @@ static bool BufferComparator(
return first->GetDecodeTimestamp() < second->GetDecodeTimestamp();
}
-// Returns the upper bound for the starting timestamp for the next buffer
-// in sequence after |buffer|. Assumes |buffer|'s timestamp and
-// duration are valid.
-static base::TimeDelta MaxNextTimestamp(
- const scoped_refptr<media::StreamParserBuffer>& buffer) {
- // Because we do not know exactly when is the next timestamp, any buffer
- // that starts within 1/3 of the duration past the end of this buffer
- // is considered the next buffer in the sequence.
- return buffer->GetEndTimestamp() + buffer->GetDuration() / 3;
-}
-
-// Returns true if |timestamp| is the timestamp of the next buffer in
-// sequence after |buffer|, false otherwise.
-static bool IsNextInSequence(
- const scoped_refptr<media::StreamParserBuffer>& buffer,
- base::TimeDelta timestamp) {
- return timestamp >= buffer->GetEndTimestamp() &&
- timestamp <= MaxNextTimestamp(buffer);
-}
+// 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;
namespace media {
-SourceBufferStream::SourceBufferStream()
- : seek_pending_(false),
- seek_buffer_timestamp_(base::TimeDelta()),
- selected_range_(NULL),
- end_of_stream_(false) {
-}
-
SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config)
: seek_pending_(false),
- seek_buffer_timestamp_(base::TimeDelta()),
+ seek_buffer_timestamp_(kNoTimestamp()),
selected_range_(NULL),
- end_of_stream_(false) {
+ end_of_stream_(false),
+ media_segment_start_time_(kNoTimestamp()),
+ range_for_next_append_(ranges_.end()),
+ new_media_segment_(false),
+ last_buffer_timestamp_(kNoTimestamp()),
+ max_interbuffer_distance_(kNoTimestamp()) {
audio_config_.CopyFrom(audio_config);
}
SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config)
: seek_pending_(false),
- seek_buffer_timestamp_(base::TimeDelta()),
+ seek_buffer_timestamp_(kNoTimestamp()),
selected_range_(NULL),
- end_of_stream_(false) {
+ end_of_stream_(false),
+ media_segment_start_time_(kNoTimestamp()),
+ range_for_next_append_(ranges_.end()),
+ new_media_segment_(false),
+ last_buffer_timestamp_(kNoTimestamp()),
+ max_interbuffer_distance_(kNoTimestamp()) {
video_config_.CopyFrom(video_config);
}
@@ -224,30 +248,68 @@ SourceBufferStream::~SourceBufferStream() {
}
}
-bool SourceBufferStream::Append(
- const SourceBufferStream::BufferQueue& buffers,
+void SourceBufferStream::OnNewMediaSegment(
base::TimeDelta media_segment_start_time) {
+ media_segment_start_time_ = media_segment_start_time;
+
+ // Find the range that will house the buffers appended through the next
+ // Append() call.
+ range_for_next_append_ = FindExistingRangeFor(media_segment_start_time);
+ new_media_segment_ = true;
+ last_buffer_timestamp_ = kNoTimestamp();
+}
+
+bool SourceBufferStream::Append(
+ const SourceBufferStream::BufferQueue& buffers) {
DCHECK(!buffers.empty());
- DCHECK(media_segment_start_time != kNoTimestamp());
+ DCHECK(media_segment_start_time_ != kNoTimestamp());
+
+ // New media segments must begin with a keyframe.
+ if (new_media_segment_ && !buffers.front()->IsKeyframe()) {
vrk (LEFT CHROMIUM) 2012/07/04 02:50:18 I added this logic here to do a proper check to ma
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 Yes. The file starts with a cluster that contains
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 Thanks Aaron! Bug filed and assigned: crbug.com/13
+ DVLOG(1) << "Media segment did not begin with keyframe.";
+ return false;
+ }
+
+ // Buffers within a media segment should be monotonically increasing.
+ if (!IsMonotonicallyIncreasing(buffers)) {
+ DVLOG(1) << "Buffers were not monotonically increasing.";
+ return false;
+ }
+
+ UpdateMaxInterbufferDistance(buffers);
+
+ // Save a snapshot of the |selected_range_| state before range modifications
+ // are made.
+ base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp();
+ base::TimeDelta end_buffer_timestamp = GetEndBufferTimestamp();
- // Find a range into which we'll append |buffers|.
- RangeList::iterator range_for_new_buffers = FindExistingRangeFor(buffers);
+ bool deleted_next_buffer = false;
+ BufferQueue deleted_buffers;
+ RangeList::iterator range_for_new_buffers = range_for_next_append_;
// If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
// create a new range with |buffers|.
if (range_for_new_buffers != ranges_.end()) {
- InsertIntoExistingRange(range_for_new_buffers, buffers);
+ InsertIntoExistingRange(range_for_new_buffers, buffers,
+ &deleted_next_buffer, &deleted_buffers);
} else {
- // Ranges must begin with a keyframe.
- if (!buffers.front()->IsKeyframe())
- return false;
+ DCHECK(new_media_segment_);
range_for_new_buffers =
- AddToRanges(new SourceBufferRange(buffers, media_segment_start_time));
+ AddToRanges(new SourceBufferRange(
+ buffers, media_segment_start_time_,
+ base::Bind(&SourceBufferStream::max_interbuffer_distance,
+ base::Unretained(this))));
}
+ range_for_next_append_ = range_for_new_buffers;
+ new_media_segment_ = false;
+ last_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
+
// Resolve overlaps.
- ResolveCompleteOverlaps(range_for_new_buffers);
- ResolveEndOverlap(range_for_new_buffers);
+ ResolveCompleteOverlaps(
+ range_for_new_buffers, &deleted_next_buffer, &deleted_buffers);
+ ResolveEndOverlap(
+ range_for_new_buffers, &deleted_next_buffer, &deleted_buffers);
MergeWithAdjacentRangeIfNecessary(range_for_new_buffers);
// If these were the first buffers appended to the stream, seek to the
@@ -258,17 +320,81 @@ bool SourceBufferStream::Append(
selected_range_->Seek(buffers.front()->GetDecodeTimestamp());
}
- // Finally, try to complete pending seek if one exists.
- if (seek_pending_)
+ // Seek to try to fulfill a previous call to Seek().
+ if (seek_pending_) {
+ DCHECK(!selected_range_);
+ DCHECK(!deleted_next_buffer);
Seek(seek_buffer_timestamp_);
+ }
+
+ // Seek because the Append() has deleted the buffer that would have been
+ // returned in the next call to GetNextBuffer().
+ if (deleted_next_buffer) {
+ DCHECK(!seek_pending_);
+ selected_range_ = *range_for_new_buffers;
+ if (!deleted_buffers.empty()) {
+ // Seek the range to the keyframe at or after |next_buffer_timestamp|.
+ selected_range_->SeekAheadTo(next_buffer_timestamp);
+ } else {
+ // If we've deleted the next buffer but |deleted_buffers| is empty,
+ // that means we need to seek past the timestamp of the last buffer in
+ // the range (i.e. the keyframe timestamp needs to be strictly greater
+ // than |end_buffer_timestamp|).
+ selected_range_->SeekAheadPast(end_buffer_timestamp);
+ }
+ UpdateTrackBuffer(deleted_buffers);
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 I believe this can be moved into the if() body abo
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 Moved UpdateTrackBuffer() accordingly. Would rath
+ }
DCHECK(IsRangeListSorted(ranges_));
return true;
}
+bool SourceBufferStream::IsMonotonicallyIncreasing(
+ const BufferQueue& buffers) {
+ DCHECK(!buffers.empty());
+ base::TimeDelta prev_timestamp = last_buffer_timestamp_;
+ for (BufferQueue::const_iterator itr = buffers.begin();
+ itr != buffers.end(); ++itr) {
+ base::TimeDelta current_timestamp = (*itr)->GetDecodeTimestamp();
+ DCHECK(current_timestamp != kNoTimestamp());
+
+ if (prev_timestamp != kNoTimestamp() && current_timestamp < prev_timestamp)
+ return false;
+
+ prev_timestamp = current_timestamp;
+ }
+ return true;
+}
+
+void SourceBufferStream::UpdateMaxInterbufferDistance(
+ const BufferQueue& buffers) {
+ DCHECK(!buffers.empty());
+ base::TimeDelta prev_timestamp = last_buffer_timestamp_;
+ for (BufferQueue::const_iterator itr = buffers.begin();
+ itr != buffers.end(); ++itr) {
+ base::TimeDelta current_timestamp = (*itr)->GetDecodeTimestamp();
+ DCHECK(current_timestamp != kNoTimestamp());
+
+ if (prev_timestamp != kNoTimestamp()) {
+ base::TimeDelta interbuffer_distance = current_timestamp - prev_timestamp;
+ if (max_interbuffer_distance_ == kNoTimestamp()) {
+ max_interbuffer_distance_ = interbuffer_distance;
+ } else {
+ max_interbuffer_distance_ =
+ std::max(max_interbuffer_distance_, interbuffer_distance);
+ }
+ }
+ prev_timestamp = current_timestamp;
+ }
+}
+
void SourceBufferStream::InsertIntoExistingRange(
const RangeList::iterator& range_for_new_buffers_itr,
- const BufferQueue& new_buffers) {
+ const BufferQueue& new_buffers,
+ bool* deleted_next_buffer, BufferQueue* deleted_buffers) {
+ DCHECK(deleted_next_buffer);
+ DCHECK(deleted_buffers);
+
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,
@@ -282,61 +408,47 @@ void SourceBufferStream::InsertIntoExistingRange(
// 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.
- base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp();
- bool had_next_buffer = range_for_new_buffers->HasNextBuffer();
SourceBufferRange* new_next_range =
- range_for_new_buffers->SplitRange(new_buffers.back()->GetEndTimestamp());
+ range_for_new_buffers->SplitRange(
+ new_buffers.back()->GetDecodeTimestamp());
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 deleted_buffers;
- range_for_new_buffers->DeleteAfter(new_buffers.front(), &deleted_buffers);
+ DCHECK(!*deleted_next_buffer);
+ *deleted_next_buffer =
+ range_for_new_buffers->TruncateAt(new_buffers.front(), deleted_buffers);
range_for_new_buffers->AppendToEnd(new_buffers);
- // If |new_buffers| doesn't overlap the selected range, no need to do anything
- // more.
- if (selected_range_ != range_for_new_buffers || !had_next_buffer ||
- next_buffer_timestamp < new_buffers.front()->GetDecodeTimestamp()) {
- return;
- }
-
// 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 (new_next_range && new_next_range->HasNextBufferPosition()) {
DCHECK(!range_for_new_buffers->HasNextBufferPosition());
+ DCHECK(!*deleted_next_buffer);
selected_range_ = new_next_range;
- return;
}
-
- selected_range_ = range_for_new_buffers;
- selected_range_->SeekAfter(next_buffer_timestamp);
- UpdateTrackBuffer(deleted_buffers);
}
void SourceBufferStream::ResolveCompleteOverlaps(
- const RangeList::iterator& range_with_new_buffers_itr) {
+ const RangeList::iterator& range_with_new_buffers_itr,
+ bool* deleted_next_buffer, BufferQueue* deleted_buffers) {
+ DCHECK(deleted_next_buffer);
+ DCHECK(deleted_buffers);
+
SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
RangeList::iterator next_range_itr = range_with_new_buffers_itr;
next_range_itr++;
- base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp();
while (next_range_itr != ranges_.end() &&
range_with_new_buffers->CompletelyOverlaps(**next_range_itr)) {
if (*next_range_itr == selected_range_) {
- // Transfer the next buffer position from the old selected range to the
- // range with the new buffers.
- selected_range_ = range_with_new_buffers;
- selected_range_->SeekAfter(next_buffer_timestamp);
-
- // Delete everything from the old selected range and save the next
- // buffers.
- BufferQueue deleted_buffers;
- (*next_range_itr)->DeleteAll(&deleted_buffers);
- UpdateTrackBuffer(deleted_buffers);
+ selected_range_ = NULL;
+ DCHECK(!*deleted_next_buffer);
+ *deleted_next_buffer = (*next_range_itr)->DeleteAll(deleted_buffers);
+ DCHECK(*deleted_next_buffer);
}
delete *next_range_itr;
next_range_itr = ranges_.erase(next_range_itr);
@@ -344,11 +456,14 @@ void SourceBufferStream::ResolveCompleteOverlaps(
}
void SourceBufferStream::ResolveEndOverlap(
- const RangeList::iterator& range_with_new_buffers_itr) {
+ const RangeList::iterator& range_with_new_buffers_itr,
+ bool* deleted_next_buffer, BufferQueue* deleted_buffers) {
+ DCHECK(deleted_next_buffer);
+ DCHECK(deleted_buffers);
+
SourceBufferRange* range_with_new_buffers = *range_with_new_buffers_itr;
RangeList::iterator next_range_itr = range_with_new_buffers_itr;
next_range_itr++;
- base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp();
if (next_range_itr == ranges_.end() ||
!range_with_new_buffers->EndOverlaps(**next_range_itr)) {
@@ -381,18 +496,10 @@ void SourceBufferStream::ResolveEndOverlap(
return;
}
- // Transfer the next buffer position from the old range to the range with
- // the new buffers.
- selected_range_ = range_with_new_buffers;
- selected_range_->SeekAfter(next_buffer_timestamp);
-
- // Update track buffer with overlapped buffers.
- BufferQueue deleted_buffers;
- scoped_refptr<StreamParserBuffer> buffer;
- while (overlapped_range->GetNextBuffer(&buffer)) {
- deleted_buffers.push_back(buffer);
- }
- UpdateTrackBuffer(deleted_buffers);
+ // Save the buffers in |overlapped_range|.
+ DCHECK(!*deleted_next_buffer);
+ *deleted_next_buffer = overlapped_range->DeleteAll(deleted_buffers);
+ DCHECK(*deleted_next_buffer);
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 nit: If we always expect DeleteAll() to return tru
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 Talked offline; leaving this as-is because technic
}
void SourceBufferStream::UpdateTrackBuffer(const BufferQueue& deleted_buffers) {
@@ -434,10 +541,11 @@ void SourceBufferStream::UpdateTrackBuffer(const BufferQueue& deleted_buffers) {
// |track_buffer_|, and if so, change |selected_range_|.
RangeList::iterator next_range_itr = ++(GetSelectedRangeItr());
if (next_range_itr != ranges_.end()) {
- (*next_range_itr)->SeekAfter(track_buffer_.back()->GetEndTimestamp());
+ (*next_range_itr)->SeekAheadPast(
+ track_buffer_.back()->GetDecodeTimestamp());
if ((*next_range_itr)->HasNextBuffer() &&
- IsNextInSequence(track_buffer_.back(),
- (*next_range_itr)->GetNextTimestamp())) {
+ selected_range_->IsNextInSequence(
+ track_buffer_.back(), (*next_range_itr)->GetNextTimestamp())) {
selected_range_ = *next_range_itr;
}
}
@@ -515,10 +623,14 @@ base::TimeDelta SourceBufferStream::GetNextBufferTimestamp() {
return selected_range_->GetNextTimestamp();
}
+base::TimeDelta SourceBufferStream::GetEndBufferTimestamp() {
+ if (!selected_range_)
+ return kNoTimestamp();
+ return selected_range_->GetEndTimestamp();
+}
+
SourceBufferStream::RangeList::iterator
-SourceBufferStream::FindExistingRangeFor(const BufferQueue& new_buffers) {
- DCHECK(!new_buffers.empty());
- base::TimeDelta start_timestamp = new_buffers.front()->GetDecodeTimestamp();
+SourceBufferStream::FindExistingRangeFor(base::TimeDelta start_timestamp) {
for (RangeList::iterator itr = ranges_.begin(); itr != ranges_.end(); itr++) {
if ((*itr)->BelongsToRange(start_timestamp))
return itr;
@@ -553,7 +665,7 @@ Ranges<base::TimeDelta> SourceBufferStream::GetBufferedTime() const {
Ranges<base::TimeDelta> ranges;
for (RangeList::const_iterator itr = ranges_.begin();
itr != ranges_.end(); itr++) {
- ranges.Add((*itr)->GetStartTimestamp(), (*itr)->GetEndTimestamp());
+ ranges.Add((*itr)->GetStartTimestamp(), (*itr)->GetBufferedEndTimestamp());
}
return ranges;
}
@@ -567,23 +679,33 @@ bool SourceBufferStream::CanEndOfStream() const {
return ranges_.empty() || selected_range_ == ranges_.back();
}
-SourceBufferRange::SourceBufferRange(const BufferQueue& new_buffers,
- base::TimeDelta media_segment_start_time)
+SourceBufferRange::SourceBufferRange(
+ const BufferQueue& new_buffers, base::TimeDelta media_segment_start_time,
+ const InterbufferDistanceCB& interbuffer_distance_cb)
: next_buffer_index_(-1),
waiting_for_keyframe_(false),
next_keyframe_timestamp_(kNoTimestamp()),
- media_segment_start_time_(media_segment_start_time) {
+ media_segment_start_time_(media_segment_start_time),
+ interbuffer_distance_cb_(interbuffer_distance_cb) {
DCHECK(!new_buffers.empty());
DCHECK(new_buffers.front()->IsKeyframe());
+ DCHECK(!interbuffer_distance_cb.is_null());
AppendToEnd(new_buffers);
}
void SourceBufferRange::AppendToEnd(const BufferQueue& new_buffers) {
+ DCHECK(!new_buffers.empty());
+ base::TimeDelta prev_timestamp = kNoTimestamp();
+ if (!buffers_.empty())
+ prev_timestamp = buffers_.back()->GetDecodeTimestamp();
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 nit: I believe this is dead code now. I don't see
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 D'oh, yes, should have reverted all changes to thi
+
for (BufferQueue::const_iterator itr = new_buffers.begin();
itr != new_buffers.end(); itr++) {
- DCHECK((*itr)->GetDuration() > base::TimeDelta());
- DCHECK((*itr)->GetDecodeTimestamp() != kNoTimestamp());
+ base::TimeDelta current_timestamp = (*itr)->GetDecodeTimestamp();
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 nit: It doesn't look like current_timestamp is use
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 Reverted.
+ DCHECK(current_timestamp != kNoTimestamp());
buffers_.push_back(*itr);
+
+ // Update keyframe index with new entry if applicable.
if ((*itr)->IsKeyframe()) {
keyframe_map_.insert(
std::make_pair((*itr)->GetDecodeTimestamp(), buffers_.size() - 1));
@@ -617,12 +739,20 @@ void SourceBufferRange::Seek(base::TimeDelta timestamp) {
DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size()));
}
-void SourceBufferRange::SeekAfter(base::TimeDelta timestamp) {
+void SourceBufferRange::SeekAheadTo(base::TimeDelta timestamp) {
+ SeekAhead(timestamp, false);
+}
+
+void SourceBufferRange::SeekAheadPast(base::TimeDelta timestamp) {
+ SeekAhead(timestamp, true);
+}
+
+void SourceBufferRange::SeekAhead(base::TimeDelta timestamp,
+ bool skip_given_timestamp) {
DCHECK(!keyframe_map_.empty());
- // lower_bound() returns the first element >= |timestamp|, so |result| is the
- // value that we want.
- KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp);
+ KeyframeMap::iterator result =
+ GetFirstKeyframeAfter(timestamp, skip_given_timestamp);
// If there isn't a keyframe after |timestamp|, then seek to end and return
// kNoTimestamp to signal such.
@@ -632,15 +762,14 @@ void SourceBufferRange::SeekAfter(base::TimeDelta timestamp) {
next_keyframe_timestamp_ = timestamp;
return;
}
-
next_buffer_index_ = result->second;
DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size()));
}
SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) {
- // Find the first keyframe after |timestamp|.
+ // Find the first keyframe after |timestamp|, not including |timestamp|.
KeyframeMap::iterator new_beginning_keyframe =
- keyframe_map_.lower_bound(timestamp);
+ GetFirstKeyframeAfter(timestamp, true);
// If there is no keyframe after |timestamp|, we can't split the range.
if (new_beginning_keyframe == keyframe_map_.end())
@@ -657,7 +786,8 @@ SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) {
// Create a new range with |removed_buffers|.
SourceBufferRange* split_range =
- new SourceBufferRange(removed_buffers, kNoTimestamp());
+ new SourceBufferRange(
+ removed_buffers, kNoTimestamp(), interbuffer_distance_cb_);
// If |next_buffer_index_| points to a buffer in |split_range|, update the
// |next_buffer_index_| of this range and |split_range| accordingly.
@@ -668,38 +798,60 @@ SourceBufferRange* SourceBufferRange::SplitRange(base::TimeDelta timestamp) {
return split_range;
}
-void SourceBufferRange::DeleteAll(BufferQueue* removed_buffers) {
- DeleteAfter(buffers_.begin(), removed_buffers);
+SourceBufferRange::KeyframeMap::iterator
+SourceBufferRange::GetFirstKeyframeAfter(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;
+}
+
+bool SourceBufferRange::DeleteAll(BufferQueue* removed_buffers) {
+ return TruncateAt(buffers_.begin(), removed_buffers);
}
-void SourceBufferRange::DeleteAfter(
+bool SourceBufferRange::TruncateAt(
scoped_refptr<StreamParserBuffer> buffer, BufferQueue* removed_buffers) {
// 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);
+ return TruncateAt(starting_point, removed_buffers);
}
-void SourceBufferRange::DeleteAfter(
+bool SourceBufferRange::TruncateAt(
const BufferQueue::iterator& starting_point, BufferQueue* removed_buffers) {
DCHECK(removed_buffers);
+ DCHECK(removed_buffers->empty());
+
// Return if we're not deleting anything.
if (starting_point == buffers_.end())
- return;
+ return false;
// Reset the next buffer index if we will be deleting the buffer that's next
// in sequence.
- if (HasNextBuffer() &&
- GetNextTimestamp() >= (*starting_point)->GetDecodeTimestamp()) {
- // Save the buffers we're about to delete if the output parameter is valid.
- int starting_offset = starting_point - buffers_.begin();
- int next_buffer_offset = next_buffer_index_ - starting_offset;
- DCHECK_GE(next_buffer_offset, 0);
- BufferQueue saved(starting_point + next_buffer_offset, buffers_.end());
- removed_buffers->swap(saved);
- next_buffer_index_ = -1;
+ bool removed_next_buffer = false;
+ if (HasNextBufferPosition()) {
+ base::TimeDelta next_buffer_timestamp = GetNextTimestamp();
+ if (next_buffer_timestamp == kNoTimestamp() ||
+ next_buffer_timestamp >= (*starting_point)->GetDecodeTimestamp()) {
+ if (HasNextBuffer()) {
+ int starting_offset = starting_point - buffers_.begin();
+ int next_buffer_offset = next_buffer_index_ - starting_offset;
+ DCHECK_GE(next_buffer_offset, 0);
+ BufferQueue saved(starting_point + next_buffer_offset, buffers_.end());
+ removed_buffers->swap(saved);
+ }
+ next_buffer_index_ = -1;
+ removed_next_buffer = true;
+ }
}
// Remove keyframes from |starting_point| onward.
@@ -709,6 +861,7 @@ void SourceBufferRange::DeleteAfter(
// Remove everything from |starting_point| onward.
buffers_.erase(starting_point, buffers_.end());
+ return removed_next_buffer;
}
bool SourceBufferRange::GetNextBuffer(
@@ -737,7 +890,7 @@ base::TimeDelta SourceBufferRange::GetNextTimestamp() const {
return next_keyframe_timestamp_;
if (next_buffer_index_ >= static_cast<int>(buffers_.size()))
- return buffers_.back()->GetEndTimestamp();
+ return kNoTimestamp();
return buffers_.at(next_buffer_index_)->GetDecodeTimestamp();
}
@@ -775,8 +928,10 @@ bool SourceBufferRange::BelongsToRange(base::TimeDelta timestamp) const {
}
bool SourceBufferRange::CanSeekTo(base::TimeDelta timestamp) const {
- return !keyframe_map_.empty() && GetStartTimestamp() <= timestamp &&
- GetEndTimestamp() > timestamp;
+ base::TimeDelta start_range =
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 nit: s/start_range/start_timestamp?
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 Done.
+ std::max(base::TimeDelta(), GetStartTimestamp() - GetFudgeRoom());
+ return !keyframe_map_.empty() && start_range <= timestamp &&
+ timestamp < GetBufferedEndTimestamp();
}
bool SourceBufferRange::CompletelyOverlaps(
@@ -786,7 +941,7 @@ bool SourceBufferRange::CompletelyOverlaps(
}
bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const {
- return range.GetStartTimestamp() < GetEndTimestamp() &&
+ return range.GetStartTimestamp() <= GetEndTimestamp() &&
GetEndTimestamp() < range.GetEndTimestamp();
}
@@ -800,7 +955,36 @@ base::TimeDelta SourceBufferRange::GetStartTimestamp() const {
base::TimeDelta SourceBufferRange::GetEndTimestamp() const {
DCHECK(!buffers_.empty());
- return buffers_.back()->GetEndTimestamp();
+ return buffers_.back()->GetDecodeTimestamp();
+}
+
+base::TimeDelta SourceBufferRange::GetBufferedEndTimestamp() const {
+ DCHECK(!buffers_.empty());
+ base::TimeDelta duration = buffers_.back()->GetDuration();
+ if (duration == kNoTimestamp() || duration == base::TimeDelta())
+ duration = GetApproximateDuration();
+ return GetEndTimestamp() + duration;
+}
+
+bool SourceBufferRange::IsNextInSequence(
+ const scoped_refptr<media::StreamParserBuffer>& buffer,
+ base::TimeDelta timestamp) const {
+ return buffer->GetDecodeTimestamp() < timestamp &&
+ timestamp <= buffer->GetDecodeTimestamp() + GetFudgeRoom();
+}
+
+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();
+}
+
+base::TimeDelta SourceBufferRange::GetApproximateDuration() const {
+ base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run();
+ if (max_interbuffer_distance == kNoTimestamp())
+ return base::TimeDelta::FromMilliseconds(kDefaultBufferDurationInMs);
acolwell GONE FROM CHROMIUM 2012/07/09 18:15:55 nit: I think the callback should always return som
vrk (LEFT CHROMIUM) 2012/07/10 00:05:33 Yes, that's a good point. Logic shuffled!
+ return max_interbuffer_distance;
}
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698