diff options
author | vrk@chromium.org <vrk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-10 04:41:21 +0000 |
---|---|---|
committer | vrk@chromium.org <vrk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-10 04:41:21 +0000 |
commit | faf4c029ac7bc1e53681edbee8c4fbdd81f81d59 (patch) | |
tree | 4af8e3586b04fe9ba8387a019aa6b37d11ae3815 /media | |
parent | ef75c230a88acecbf9ae76829c6eb795a9815d74 (diff) | |
download | chromium_src-faf4c029ac7bc1e53681edbee8c4fbdd81f81d59.zip chromium_src-faf4c029ac7bc1e53681edbee8c4fbdd81f81d59.tar.gz chromium_src-faf4c029ac7bc1e53681edbee8c4fbdd81f81d59.tar.bz2 |
Remove buffer duration calculation from WebMClusterParser and update SourceBufferStream accordingly
This removes the work to calculate buffers' durations in WebMClusterParser and
modifies SourceBufferStream to no longer need duration information to work. This
allows us to fix several bugs.
BUG=131695,136418
TEST=media_unittests, go/oiedsb no longer needs Abort()s to work
Review URL: https://chromiumcodereview.appspot.com/10692053
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@145839 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/stream_parser_buffer.cc | 7 | ||||
-rw-r--r-- | media/base/stream_parser_buffer.h | 3 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.cc | 22 | ||||
-rw-r--r-- | media/filters/chunk_demuxer_unittest.cc | 117 | ||||
-rw-r--r-- | media/filters/source_buffer_stream.cc | 477 | ||||
-rw-r--r-- | media/filters/source_buffer_stream.h | 70 | ||||
-rw-r--r-- | media/filters/source_buffer_stream_unittest.cc | 299 | ||||
-rw-r--r-- | media/webm/webm_cluster_parser.cc | 82 | ||||
-rw-r--r-- | media/webm/webm_cluster_parser.h | 12 |
9 files changed, 614 insertions, 475 deletions
diff --git a/media/base/stream_parser_buffer.cc b/media/base/stream_parser_buffer.cc index 4dc7252..8501372 100644 --- a/media/base/stream_parser_buffer.cc +++ b/media/base/stream_parser_buffer.cc @@ -28,12 +28,6 @@ void StreamParserBuffer::SetDecodeTimestamp(const base::TimeDelta& timestamp) { decode_timestamp_ = timestamp; } -base::TimeDelta StreamParserBuffer::GetEndTimestamp() const { - DCHECK(GetDecodeTimestamp() != kNoTimestamp()); - DCHECK(GetDuration() != kNoTimestamp()); - return GetDecodeTimestamp() + GetDuration(); -} - StreamParserBuffer::StreamParserBuffer(const uint8* data, int data_size, bool is_keyframe) : DecoderBuffer(data, data_size), @@ -42,7 +36,6 @@ StreamParserBuffer::StreamParserBuffer(const uint8* data, int data_size, SetDuration(kNoTimestamp()); } - StreamParserBuffer::~StreamParserBuffer() { } diff --git a/media/base/stream_parser_buffer.h b/media/base/stream_parser_buffer.h index fa3c64f..da7f64f 100644 --- a/media/base/stream_parser_buffer.h +++ b/media/base/stream_parser_buffer.h @@ -22,9 +22,6 @@ class MEDIA_EXPORT StreamParserBuffer : public DecoderBuffer { base::TimeDelta GetDecodeTimestamp() const; void SetDecodeTimestamp(const base::TimeDelta& timestamp); - // Returns this buffer's decode timestamp + duration, assuming both are valid. - base::TimeDelta GetEndTimestamp() const; - private: StreamParserBuffer(const uint8* data, int data_size, bool is_keyframe); virtual ~StreamParserBuffer(); diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 0763493..d4e5ce9 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -157,7 +157,6 @@ class ChunkDemuxerStream : public DemuxerStream { void StartWaitingForSeek(); void Seek(TimeDelta time); bool IsSeekPending() const; - void Flush(); // Add buffers to this stream. Buffers are stored in SourceBufferStreams, // which handle ordering and overlap resolution. @@ -216,17 +215,12 @@ class ChunkDemuxerStream : public DemuxerStream { State state_; ReadCBQueue read_cbs_; - // The timestamp of the current media segment being parsed by - // |stream_parser_|. - TimeDelta media_segment_start_time_; - DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); }; ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config) : type_(AUDIO), - state_(RETURNING_DATA_FOR_READS), - media_segment_start_time_(kNoTimestamp()) { + state_(RETURNING_DATA_FOR_READS) { stream_.reset(new SourceBufferStream(audio_config)); } @@ -266,12 +260,9 @@ bool ChunkDemuxerStream::IsSeekPending() const { return stream_->IsSeekPending(); } -void ChunkDemuxerStream::Flush() { - media_segment_start_time_ = kNoTimestamp(); -} - void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { - media_segment_start_time_ = start_timestamp; + base::AutoLock auto_lock(lock_); + stream_->OnNewMediaSegment(start_timestamp); } bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) { @@ -282,8 +273,7 @@ bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) { { base::AutoLock auto_lock(lock_); DCHECK_NE(state_, SHUTDOWN); - DCHECK(media_segment_start_time_ != kNoTimestamp()); - if (!stream_->Append(buffers, media_segment_start_time_)) { + if (!stream_->Append(buffers)) { DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed"; return false; } @@ -759,10 +749,6 @@ void ChunkDemuxer::Abort(const std::string& id) { DCHECK_GT(stream_parser_map_.count(id), 0u); stream_parser_map_[id]->Flush(); - if (audio_ && source_id_audio_ == id) - audio_->Flush(); - if (video_ && source_id_video_ == id) - video_->Flush(); } bool ChunkDemuxer::EndOfStream(PipelineStatus status) { diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index 2494c9f..cde3417 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc @@ -236,8 +236,7 @@ class ChunkDemuxerTest : public testing::Test { bool AppendData(const std::string& source_id, const uint8* data, size_t length) { CHECK(length); - EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber()) - .WillRepeatedly(SaveArg<1>(&buffered_time_)); + EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber()); return demuxer_->AppendData(source_id, data, length); } @@ -249,14 +248,11 @@ class ChunkDemuxerTest : public testing::Test { const uint8* start = data; const uint8* end = data + length; while (start < end) { - base::TimeDelta old_buffered_time = buffered_time_; size_t append_size = std::min(piece_size, static_cast<size_t>(end - start)); if (!AppendData(start, append_size)) return false; start += append_size; - - EXPECT_GE(buffered_time_, old_buffered_time); } return true; } @@ -572,7 +568,6 @@ class ChunkDemuxerTest : public testing::Test { } MockDemuxerHost host_; - base::TimeDelta buffered_time_; scoped_ptr<MockChunkDemuxerClient> client_; scoped_refptr<ChunkDemuxer> demuxer_; @@ -828,34 +823,6 @@ TEST_F(ChunkDemuxerTest, TestPerStreamMonotonicallyIncreasingTimestamps) { ASSERT_TRUE(AppendData(cluster->data(), cluster->size())); } -TEST_F(ChunkDemuxerTest, TestMonotonicallyIncreasingTimestampsAcrossClusters) { - ASSERT_TRUE(InitDemuxer(true, true, false)); - - ClusterBuilder cb; - - // Test monotonic increasing timestamps on a per stream - // basis across clusters. - cb.SetClusterTimecode(5); - AddSimpleBlock(&cb, kAudioTrackNum, 5); - AddSimpleBlock(&cb, kVideoTrackNum, 5); - scoped_ptr<Cluster> cluster_a(cb.Finish()); - - ASSERT_TRUE(AppendData(cluster_a->data(), cluster_a->size())); - - cb.SetClusterTimecode(4); - AddSimpleBlock(&cb, kAudioTrackNum, 4); - AddSimpleBlock(&cb, kVideoTrackNum, 7); - scoped_ptr<Cluster> cluster_b(cb.Finish()); - - EXPECT_CALL(host_, OnDemuxerError(PIPELINE_ERROR_DECODE)); - ASSERT_TRUE(AppendData(cluster_b->data(), cluster_b->size())); - - // Verify that AppendData() doesn't accept more data now. - scoped_ptr<Cluster> cluster_c(GenerateCluster(10, 2)); - EXPECT_FALSE(demuxer_->AppendData(kSourceId, cluster_c->data(), - cluster_c->size())); -} - // Test the case where a cluster is passed to AppendData() before // INFO & TRACKS data. TEST_F(ChunkDemuxerTest, TestClusterBeforeInitSegment) { @@ -1100,7 +1067,9 @@ TEST_F(ChunkDemuxerTest, TestWebMFile_AudioAndVideo) { base::TimeDelta::FromMilliseconds(2744))); } -TEST_F(ChunkDemuxerTest, TestWebMFile_LiveAudioAndVideo) { +// TODO(acolwell): Fix bear-320x240-live.webm so that all clusters begin with +// keyframes and reenable test. (crbug.com/136438) +TEST_F(ChunkDemuxerTest, DISABLED_TestWebMFile_LiveAudioAndVideo) { struct BufferTimestamps buffer_timestamps[] = { {0, 0}, {33, 3}, @@ -1474,12 +1443,12 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_VideoIdOnly) { CheckExpectedRanges("{ [0,132) }"); // Append a disjoint cluster to check for two separate ranges. - scoped_ptr<Cluster> cluster_2(GenerateSingleStreamCluster(150, 249, + scoped_ptr<Cluster> cluster_2(GenerateSingleStreamCluster(200, 299, kVideoTrackNum, kVideoBlockDuration)); ASSERT_TRUE(AppendData(cluster_2->data(), cluster_2->size())); - CheckExpectedRanges("{ [0,132) [150,249) }"); + CheckExpectedRanges("{ [0,132) [200,299) }"); } TEST_F(ChunkDemuxerTest, GetBufferedRanges_AudioVideo) { @@ -1503,74 +1472,74 @@ TEST_F(ChunkDemuxerTest, GetBufferedRanges_AudioVideo) { CheckExpectedRanges("{ [0,23) }"); - // Audio: 100 -> 150 - // Video: 120 -> 170 - // Buffered Range: 120 -> 150 (end overlap) + // Audio: 300 -> 400 + // Video: 320 -> 420 + // Buffered Range: 320 -> 400 (end overlap) scoped_ptr<Cluster> cluster_a1( - GenerateSingleStreamCluster(100, 150, kAudioTrackNum, 50)); + GenerateSingleStreamCluster(300, 400, kAudioTrackNum, 50)); scoped_ptr<Cluster> cluster_v1( - GenerateSingleStreamCluster(120, 170, kVideoTrackNum, 50)); + GenerateSingleStreamCluster(320, 420, kVideoTrackNum, 50)); ASSERT_TRUE(AppendData(cluster_a1->data(), cluster_a1->size())); ASSERT_TRUE(AppendData(cluster_v1->data(), cluster_v1->size())); - CheckExpectedRanges("{ [0,23) [120,150) }"); + CheckExpectedRanges("{ [0,23) [320,400) }"); - // Audio: 220 -> 290 - // Video: 200 -> 270 - // Buffered Range: 220 -> 270 (front overlap) + // Audio: 520 -> 590 + // Video: 500 -> 570 + // Buffered Range: 520 -> 570 (front overlap) scoped_ptr<Cluster> cluster_a2( - GenerateSingleStreamCluster(220, 290, kAudioTrackNum, 70)); + GenerateSingleStreamCluster(520, 590, kAudioTrackNum, 70)); scoped_ptr<Cluster> cluster_v2( - GenerateSingleStreamCluster(200, 270, kVideoTrackNum, 70)); + GenerateSingleStreamCluster(500, 570, kVideoTrackNum, 70)); ASSERT_TRUE(AppendData(cluster_a2->data(), cluster_a2->size())); ASSERT_TRUE(AppendData(cluster_v2->data(), cluster_v2->size())); - CheckExpectedRanges("{ [0,23) [120,150) [220,270) }"); + CheckExpectedRanges("{ [0,23) [320,400) [520,570) }"); - // Audio: 320 -> 350 - // Video: 300 -> 370 - // Buffered Range: 320 -> 350 (complete overlap, audio) + // Audio: 720 -> 750 + // Video: 700 -> 770 + // Buffered Range: 720 -> 750 (complete overlap, audio) scoped_ptr<Cluster> cluster_a3( - GenerateSingleStreamCluster(320, 350, kAudioTrackNum, 30)); + GenerateSingleStreamCluster(720, 750, kAudioTrackNum, 30)); scoped_ptr<Cluster> cluster_v3( - GenerateSingleStreamCluster(300, 370, kVideoTrackNum, 70)); + GenerateSingleStreamCluster(700, 770, kVideoTrackNum, 70)); ASSERT_TRUE(AppendData(cluster_a3->data(), cluster_a3->size())); ASSERT_TRUE(AppendData(cluster_v3->data(), cluster_v3->size())); - CheckExpectedRanges("{ [0,23) [120,150) [220,270) [320,350) }"); + CheckExpectedRanges("{ [0,23) [320,400) [520,570) [720,750) }"); - // Audio: 400 -> 470 - // Video: 420 -> 450 - // Buffered Range: 420 -> 450 (complete overlap, video) + // Audio: 900 -> 970 + // Video: 920 -> 950 + // Buffered Range: 920 -> 950 (complete overlap, video) scoped_ptr<Cluster> cluster_a4( - GenerateSingleStreamCluster(400, 470, kAudioTrackNum, 70)); + GenerateSingleStreamCluster(900, 970, kAudioTrackNum, 70)); scoped_ptr<Cluster> cluster_v4( - GenerateSingleStreamCluster(420, 450, kVideoTrackNum, 30)); + GenerateSingleStreamCluster(920, 950, kVideoTrackNum, 30)); ASSERT_TRUE(AppendData(cluster_a4->data(), cluster_a4->size())); ASSERT_TRUE(AppendData(cluster_v4->data(), cluster_v4->size())); - CheckExpectedRanges("{ [0,23) [120,150) [220,270) [320,350) [420,450) }"); + CheckExpectedRanges("{ [0,23) [320,400) [520,570) [720,750) [920,950) }"); // Appending within buffered range should not affect buffered ranges. scoped_ptr<Cluster> cluster_a5( - GenerateSingleStreamCluster(430, 450, kAudioTrackNum, 20)); + GenerateSingleStreamCluster(930, 950, kAudioTrackNum, 20)); ASSERT_TRUE(AppendData(cluster_a5->data(), cluster_a5->size())); - CheckExpectedRanges("{ [0,23) [120,150) [220,270) [320,350) [420,450) }"); + CheckExpectedRanges("{ [0,23) [320,400) [520,570) [720,750) [920,950) }"); // Appending to single stream outside buffered ranges should not affect // buffered ranges. scoped_ptr<Cluster> cluster_v5( - GenerateSingleStreamCluster(530, 540, kVideoTrackNum, 10)); + GenerateSingleStreamCluster(1230, 1240, kVideoTrackNum, 10)); ASSERT_TRUE(AppendData(cluster_v5->data(), cluster_v5->size())); - CheckExpectedRanges("{ [0,23) [120,150) [220,270) [320,350) [420,450) }"); + CheckExpectedRanges("{ [0,23) [320,400) [520,570) [720,750) [920,950) }"); } // Once EndOfStream() is called, GetBufferedRanges should not cut off any @@ -1663,20 +1632,20 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamFailures) { ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id)); scoped_ptr<Cluster> cluster_a1( - GenerateSingleStreamCluster(0, 15, kAudioTrackNum, 15)); + GenerateSingleStreamCluster(0, 35, kAudioTrackNum, 35)); scoped_ptr<Cluster> cluster_v1( - GenerateSingleStreamCluster(0, 5, kVideoTrackNum, 5)); + GenerateSingleStreamCluster(0, 10, kVideoTrackNum, 5)); scoped_ptr<Cluster> cluster_v2( - GenerateSingleStreamCluster(5, 10, kVideoTrackNum, 5)); + GenerateSingleStreamCluster(10, 25, kVideoTrackNum, 5)); scoped_ptr<Cluster> cluster_v3( - GenerateSingleStreamCluster(10, 20, kVideoTrackNum, 10)); + GenerateSingleStreamCluster(30, 50, kVideoTrackNum, 10)); ASSERT_TRUE(AppendData(audio_id, cluster_a1->data(), cluster_a1->size())); ASSERT_TRUE(AppendData(video_id, cluster_v1->data(), cluster_v1->size())); ASSERT_TRUE(AppendData(video_id, cluster_v3->data(), cluster_v3->size())); - CheckExpectedRanges(audio_id, "{ [0,15) }"); - CheckExpectedRanges(video_id, "{ [0,5) [10,20) }"); + CheckExpectedRanges(audio_id, "{ [0,35) }"); + CheckExpectedRanges(video_id, "{ [0,10) [30,50) }"); // Make sure that end of stream fails because there is a gap between // the current position(0) and the end of the appended data. @@ -1685,7 +1654,7 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamFailures) { // Seek to an time that is inside the last ranges for both streams // and verify that the EndOfStream() is successful. demuxer_->StartWaitingForSeek(); - demuxer_->Seek(base::TimeDelta::FromMilliseconds(10), + demuxer_->Seek(base::TimeDelta::FromMilliseconds(30), NewExpectedStatusCB(PIPELINE_OK)); ASSERT_TRUE(demuxer_->EndOfStream(PIPELINE_OK)); @@ -1700,8 +1669,8 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamFailures) { // Append the missing range and verify that EndOfStream() succeeds now. ASSERT_TRUE(AppendData(video_id, cluster_v2->data(), cluster_v2->size())); - CheckExpectedRanges(audio_id, "{ [0,15) }"); - CheckExpectedRanges(video_id, "{ [0,20) }"); + CheckExpectedRanges(audio_id, "{ [0,35) }"); + CheckExpectedRanges(video_id, "{ [0,50) }"); ASSERT_TRUE(demuxer_->EndOfStream(PIPELINE_OK)); } diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc index 2f20009..2b1911a 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,18 @@ class SourceBufferRange { public: typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; + // Returns the maximum distance in time between any buffer seen in this + // stream. Used to estimate the duration of a buffer if its duration is not + // known. + typedef base::Callback<base::TimeDelta()> InterbufferDistanceCB; + // 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 +53,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 +73,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 +96,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 +127,42 @@ 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); + + // 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|. + KeyframeMap::iterator GetFirstKeyframeAt( + 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 +187,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 +201,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 +216,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 +255,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()); - // Find a range into which we'll append |buffers|. - RangeList::iterator range_for_new_buffers = FindExistingRangeFor(buffers); + // New media segments must begin with a keyframe. + if (new_media_segment_ && !buffers.front()->IsKeyframe()) { + 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(); + + 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::GetMaxInterbufferDistance, + 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 +327,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); + UpdateTrackBuffer(deleted_buffers); + } 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); + } + } 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 +415,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 +463,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,22 +503,15 @@ 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); } void SourceBufferStream::UpdateTrackBuffer(const BufferQueue& deleted_buffers) { - if (!track_buffer_.empty() || deleted_buffers.empty()) + DCHECK(!deleted_buffers.empty()); + if (!track_buffer_.empty()) return; DCHECK(selected_range_); @@ -434,10 +549,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 +631,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 +673,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,21 +687,29 @@ bool SourceBufferStream::CanEndOfStream() const { return ranges_.empty() || selected_range_ == ranges_.back(); } -SourceBufferRange::SourceBufferRange(const BufferQueue& new_buffers, - base::TimeDelta media_segment_start_time) +base::TimeDelta SourceBufferStream::GetMaxInterbufferDistance() const { + if (max_interbuffer_distance_ == kNoTimestamp()) + return base::TimeDelta::FromMilliseconds(kDefaultBufferDurationInMs); + return max_interbuffer_distance_; +} + +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) { for (BufferQueue::const_iterator itr = new_buffers.begin(); itr != new_buffers.end(); itr++) { - DCHECK((*itr)->GetDuration() > base::TimeDelta()); DCHECK((*itr)->GetDecodeTimestamp() != kNoTimestamp()); buffers_.push_back(*itr); if ((*itr)->IsKeyframe()) { @@ -617,12 +745,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 = + GetFirstKeyframeAt(timestamp, skip_given_timestamp); // If there isn't a keyframe after |timestamp|, then seek to end and return // kNoTimestamp to signal such. @@ -632,15 +768,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); + GetFirstKeyframeAt(timestamp, true); // If there is no keyframe after |timestamp|, we can't split the range. if (new_beginning_keyframe == keyframe_map_.end()) @@ -657,7 +792,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 +804,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::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; +} + +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 +867,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 +896,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 +934,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_timestamp = + std::max(base::TimeDelta(), GetStartTimestamp() - GetFudgeRoom()); + return !keyframe_map_.empty() && start_timestamp <= timestamp && + timestamp < GetBufferedEndTimestamp(); } bool SourceBufferRange::CompletelyOverlaps( @@ -786,7 +947,7 @@ bool SourceBufferRange::CompletelyOverlaps( } bool SourceBufferRange::EndOverlaps(const SourceBufferRange& range) const { - return range.GetStartTimestamp() < GetEndTimestamp() && + return range.GetStartTimestamp() <= GetEndTimestamp() && GetEndTimestamp() < range.GetEndTimestamp(); } @@ -800,7 +961,35 @@ 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(); + DCHECK(max_interbuffer_distance != kNoTimestamp()); + return max_interbuffer_distance; } } // namespace media diff --git a/media/filters/source_buffer_stream.h b/media/filters/source_buffer_stream.h index db2a92f..3f4a211 100644 --- a/media/filters/source_buffer_stream.h +++ b/media/filters/source_buffer_stream.h @@ -28,22 +28,22 @@ class MEDIA_EXPORT SourceBufferStream { public: typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; - SourceBufferStream(); explicit SourceBufferStream(const AudioDecoderConfig& audio_config); explicit SourceBufferStream(const VideoDecoderConfig& video_config); ~SourceBufferStream(); + // Signals that the next buffers appended are part of a new media segment + // starting at |media_segment_start_time|. + void OnNewMediaSegment(base::TimeDelta media_segment_start_time); + // Add the |buffers| to the SourceBufferStream. Buffers within the queue are // expected to be in order, but multiple calls to Append() may add buffers out // of order or overlapping. Assumes all buffers within |buffers| are in // presentation order and are non-overlapping. - // |media_segment_start_time| refers to the starting timestamp for the media - // segment to which these buffers belong. // Returns true if Append() was successful, false if |buffers| are not added. // TODO(vrk): Implement garbage collection. (crbug.com/125070) - bool Append(const BufferQueue& buffers, - base::TimeDelta media_segment_start_time); + bool Append(const BufferQueue& buffers); // Changes the SourceBufferStream's state so that it will start returning // buffers starting from the closest keyframe before |timestamp|. @@ -82,21 +82,40 @@ class MEDIA_EXPORT SourceBufferStream { return video_config_; } + // Returns the largest distance between two adjacent buffers in this stream, + // or an estimate if no two adjacent buffers have been appended to the stream + // yet. + base::TimeDelta GetMaxInterbufferDistance() const; + private: typedef std::list<SourceBufferRange*> RangeList; // Appends |new_buffers| into |range_for_new_buffers_itr|, handling start and // end overlaps if necessary. + // |deleted_next_buffer| is an output parameter that is true if the next + // buffer that would have been returned from GetNextBuffer() was deleted + // during this call. + // |deleted_buffers| is an output parameter containing candidates for + // |track_buffer_|. void InsertIntoExistingRange( const RangeList::iterator& range_for_new_buffers_itr, - const BufferQueue& new_buffers); + const BufferQueue& new_buffers, + bool* deleted_next_buffer, BufferQueue* deleted_buffers); // Resolve overlapping ranges such that no ranges overlap anymore. // |range_with_new_buffers_itr| points to the range that has newly appended // buffers. + // |deleted_next_buffer| is an output parameter that is true if the next + // buffer that would have been returned from GetNextBuffer() was deleted + // during this call. + // |deleted_buffers| is an output parameter containing candidates for + // |track_buffer_|. void ResolveCompleteOverlaps( - const RangeList::iterator& range_with_new_buffers_itr); - void ResolveEndOverlap(const RangeList::iterator& range_with_new_buffers_itr); + const RangeList::iterator& range_with_new_buffers_itr, + bool* deleted_next_buffer, BufferQueue* deleted_buffers); + void ResolveEndOverlap( + const RangeList::iterator& range_with_new_buffers_itr, + bool* deleted_next_buffer, BufferQueue* deleted_buffers); // This method is a bit tricky to describe. When what would have been the // next buffer returned from |selected_range_| is overlapped by new data, @@ -119,10 +138,14 @@ class MEDIA_EXPORT SourceBufferStream { // if in between seeking (i.e. |selected_range_| is null). base::TimeDelta GetNextBufferTimestamp(); - // Finds the range into which |new_buffers| should be inserted and returns the - // iterator pointing to it. Returns |ranges_.end()| if no existing range - // should contain |new_buffers|. - RangeList::iterator FindExistingRangeFor(const BufferQueue& new_buffers); + // Returns the timestamp of the last buffer in the |selected_range_| or + // kNoTimestamp() if |selected_range_| is null. + base::TimeDelta GetEndBufferTimestamp(); + + // Finds the range that should contain a media segment that begins with + // |start_timestamp| and returns the iterator pointing to it. Returns + // |ranges_.end()| if there's no such existing range. + RangeList::iterator FindExistingRangeFor(base::TimeDelta start_timestamp); // Inserts |new_range| into |ranges_| preserving sorted order. Returns an // iterator in |ranges_| that points to |new_range|. @@ -132,6 +155,13 @@ class MEDIA_EXPORT SourceBufferStream { // |selected_range_| lives. RangeList::iterator GetSelectedRangeItr(); + // Returns true if the timestamps of |buffers| are monotonically increasing + // since the previous append to the media segment, false otherwise. + bool IsMonotonicallyIncreasing(const BufferQueue& buffers); + + // Measures the distances between buffer timestamps and tracks the max. + void UpdateMaxInterbufferDistance(const BufferQueue& buffers); + // List of disjoint buffered ranges, ordered by start time. RangeList ranges_; @@ -158,6 +188,22 @@ class MEDIA_EXPORT SourceBufferStream { // EOS buffers for read requests beyond the buffered data. False initially. bool end_of_stream_; + // The start time of the current media segment being appended. + base::TimeDelta media_segment_start_time_; + + // Points to the range containing the current media segment being appended. + RangeList::iterator range_for_next_append_; + + // True when the next call to Append() begins a new media segment. + bool new_media_segment_; + + // The timestamp of the last buffer appended to the media segment, set to + // kNoTimestamp() if the beginning of the segment. + base::TimeDelta last_buffer_timestamp_; + + // Stores the largest distance between two adjacent buffers in this stream. + base::TimeDelta max_interbuffer_distance_; + DISALLOW_COPY_AND_ASSIGN(SourceBufferStream); }; diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc index 8dbf69d..3a11661 100644 --- a/media/filters/source_buffer_stream_unittest.cc +++ b/media/filters/source_buffer_stream_unittest.cc @@ -19,6 +19,7 @@ static const int kDataSize = 1; class SourceBufferStreamTest : public testing::Test { protected: SourceBufferStreamTest() { + stream_.reset(new SourceBufferStream(config_)); SetStreamInfo(kDefaultFramesPerSecond, kDefaultKeyframesPerSecond); } @@ -28,35 +29,47 @@ class SourceBufferStreamTest : public testing::Test { frame_duration_ = ConvertToFrameDuration(frames_per_second); } - void AppendBuffers(int starting_position, int number_of_buffers) { - AppendBuffers(starting_position, number_of_buffers, + void NewSegmentAppend(int starting_position, int number_of_buffers) { + AppendBuffers(starting_position, number_of_buffers, true, base::TimeDelta(), true, NULL, 0); } - void AppendBuffers(int starting_position, int number_of_buffers, - const uint8* data) { - AppendBuffers(starting_position, number_of_buffers, + void NewSegmentAppend(int starting_position, int number_of_buffers, + const uint8* data) { + AppendBuffers(starting_position, number_of_buffers, true, base::TimeDelta(), true, data, kDataSize); } - void AppendBuffers(int starting_position, int number_of_buffers, - base::TimeDelta first_buffer_offset) { - AppendBuffers(starting_position, number_of_buffers, + void NewSegmentAppend_OffsetFirstBuffer( + int starting_position, int number_of_buffers, + base::TimeDelta first_buffer_offset) { + AppendBuffers(starting_position, number_of_buffers, true, first_buffer_offset, true, NULL, 0); } - void AppendBuffers_ExpectFailure( + void NewSegmentAppend_ExpectFailure( int starting_position, int number_of_buffers) { - AppendBuffers(starting_position, number_of_buffers, + AppendBuffers(starting_position, number_of_buffers, true, base::TimeDelta(), false, NULL, 0); } + void AppendBuffers(int starting_position, int number_of_buffers) { + AppendBuffers(starting_position, number_of_buffers, false, + base::TimeDelta(), true, NULL, 0); + } + + void AppendBuffers(int starting_position, int number_of_buffers, + const uint8* data) { + AppendBuffers(starting_position, number_of_buffers, false, + base::TimeDelta(), true, data, kDataSize); + } + void Seek(int position) { - stream_.Seek(position * frame_duration_); + stream_->Seek(position * frame_duration_); } void CheckExpectedRanges(const std::string& expected) { - Ranges<base::TimeDelta> r = stream_.GetBufferedTime(); + Ranges<base::TimeDelta> r = stream_->GetBufferedTime(); std::stringstream ss; ss << "{ "; @@ -99,7 +112,7 @@ class SourceBufferStreamTest : public testing::Test { int current_position = starting_position; for (; current_position <= ending_position; current_position++) { scoped_refptr<StreamParserBuffer> buffer; - if (!stream_.GetNextBuffer(&buffer)) + if (!stream_->GetNextBuffer(&buffer)) break; if (expect_keyframe && current_position == starting_position) @@ -123,12 +136,13 @@ class SourceBufferStreamTest : public testing::Test { void CheckNoNextBuffer() { scoped_refptr<StreamParserBuffer> buffer; - EXPECT_FALSE(stream_.GetNextBuffer(&buffer)); + EXPECT_FALSE(stream_->GetNextBuffer(&buffer)); } base::TimeDelta frame_duration() const { return frame_duration_; } - SourceBufferStream stream_; + scoped_ptr<SourceBufferStream> stream_; + VideoDecoderConfig config_; private: base::TimeDelta ConvertToFrameDuration(int frames_per_second) { @@ -136,12 +150,17 @@ class SourceBufferStreamTest : public testing::Test { base::Time::kMicrosecondsPerSecond / frames_per_second); } - void AppendBuffers(int starting_position, int number_of_buffers, + void AppendBuffers(int starting_position, + int number_of_buffers, + bool begin_media_segment, base::TimeDelta first_buffer_offset, - bool expect_success, const uint8* data, int size) { + bool expect_success, + const uint8* data, + int size) { + if (begin_media_segment) + stream_->OnNewMediaSegment(starting_position * frame_duration_); + int keyframe_interval = frames_per_second_ / keyframes_per_second_; - base::TimeDelta media_segment_start_time = - starting_position * frame_duration_; SourceBufferStream::BufferQueue queue; for (int i = 0; i < number_of_buffers; i++) { @@ -149,13 +168,10 @@ class SourceBufferStreamTest : public testing::Test { bool is_keyframe = position % keyframe_interval == 0; scoped_refptr<StreamParserBuffer> buffer = StreamParserBuffer::CopyFrom(data, size, is_keyframe); - base::TimeDelta duration = frame_duration_; base::TimeDelta timestamp = frame_duration_ * position; - if (i == 0) { - duration -= first_buffer_offset; + + if (i == 0) timestamp += first_buffer_offset; - } - buffer->SetDuration(duration); buffer->SetDecodeTimestamp(timestamp); // Simulate an IBB...BBP pattern in which all B-frames reference both @@ -175,7 +191,8 @@ class SourceBufferStreamTest : public testing::Test { queue.push_back(buffer); } - EXPECT_EQ(stream_.Append(queue, media_segment_start_time), expect_success); + if (!queue.empty()) + EXPECT_EQ(expect_success, stream_->Append(queue)); } int frames_per_second_; @@ -186,7 +203,7 @@ class SourceBufferStreamTest : public testing::Test { TEST_F(SourceBufferStreamTest, Append_SingleRange) { // Append 15 buffers at positions 0 through 14. - AppendBuffers(0, 15); + NewSegmentAppend(0, 15); // Check expected range. CheckExpectedRanges("{ [0,14) }"); @@ -197,7 +214,8 @@ TEST_F(SourceBufferStreamTest, Append_SingleRange) { TEST_F(SourceBufferStreamTest, Append_SingleRange_OneBufferAtATime) { // Append 15 buffers starting at position 0, one buffer at a time. - for (int i = 0; i < 15; i++) + NewSegmentAppend(0, 1); + for (int i = 1; i < 15; i++) AppendBuffers(i, 1); // Check expected range. @@ -209,10 +227,10 @@ TEST_F(SourceBufferStreamTest, Append_SingleRange_OneBufferAtATime) { TEST_F(SourceBufferStreamTest, Append_DisjointRanges) { // Append 5 buffers at positions 0 through 4. - AppendBuffers(0, 5); + NewSegmentAppend(0, 5); // Append 10 buffers at positions 15 through 24. - AppendBuffers(15, 10); + NewSegmentAppend(15, 10); // Check expected ranges. CheckExpectedRanges("{ [0,4) [15,24) }"); @@ -224,14 +242,14 @@ TEST_F(SourceBufferStreamTest, Append_DisjointRanges) { } TEST_F(SourceBufferStreamTest, Append_AdjacentRanges) { - // Append 12 buffers at positions 0 through 11. - AppendBuffers(0, 12); + // Append 10 buffers at positions 0 through 9. + NewSegmentAppend(0, 10); // Append 11 buffers at positions 15 through 25. - AppendBuffers(15, 11); + NewSegmentAppend(15, 11); - // Append 3 buffers at positions 12 through 14 to bridge the gap. - AppendBuffers(12, 3); + // Append 5 buffers at positions 10 through 14 to bridge the gap. + NewSegmentAppend(10, 5); // Check expected range. CheckExpectedRanges("{ [0,25) }"); @@ -242,10 +260,10 @@ TEST_F(SourceBufferStreamTest, Append_AdjacentRanges) { TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe) { // Append fails because the range doesn't begin with a keyframe. - AppendBuffers_ExpectFailure(3, 5); + NewSegmentAppend_ExpectFailure(3, 2); // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10); + NewSegmentAppend(5, 10); // Check expected range. CheckExpectedRanges("{ [5,14) }"); @@ -254,18 +272,34 @@ TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe) { CheckExpectedBuffers(5, 14); // Append fails because the range doesn't begin with a keyframe. - AppendBuffers_ExpectFailure(17, 10); + NewSegmentAppend_ExpectFailure(17, 3); + CheckExpectedRanges("{ [5,14) }"); Seek(5); CheckExpectedBuffers(5, 14); } +TEST_F(SourceBufferStreamTest, Append_DoesNotBeginWithKeyframe_Adjacent) { + // Append 8 buffers at positions 0 through 7. + NewSegmentAppend(0, 8); + + // Now start a new media segment at position 8. Append should fail because + // the media segment does not begin with a keyframe. + NewSegmentAppend_ExpectFailure(8, 2); + + // Check expected range. + CheckExpectedRanges("{ [0,7) }"); + // Check buffers in range. + Seek(0); + CheckExpectedBuffers(0, 7); +} + TEST_F(SourceBufferStreamTest, Complete_Overlap) { // Append 5 buffers at positions 5 through 9. - AppendBuffers(5, 5); + NewSegmentAppend(5, 5); // Append 15 buffers at positions 0 through 14. - AppendBuffers(0, 15); + NewSegmentAppend(0, 15); // Check expected range. CheckExpectedRanges("{ [0,14) }"); @@ -280,10 +314,10 @@ TEST_F(SourceBufferStreamTest, Complete_Overlap_EdgeCase) { SetStreamInfo(30, 30); // Append 6 buffers at positions 6 through 11. - AppendBuffers(6, 6); + NewSegmentAppend(6, 6); // Append 8 buffers at positions 5 through 12. - AppendBuffers(5, 8); + NewSegmentAppend(5, 8); // Check expected range. CheckExpectedRanges("{ [5,12) }"); @@ -293,25 +327,25 @@ TEST_F(SourceBufferStreamTest, Complete_Overlap_EdgeCase) { } TEST_F(SourceBufferStreamTest, Start_Overlap) { - // Append 5 buffers at positions 5 through 9. - AppendBuffers(5, 5); + // Append 10 buffers at positions 5 through 14. + NewSegmentAppend(5, 5); - // Append 6 buffers at positions 8 through 13. - AppendBuffers(8, 6); + // Append 6 buffers at positions 10 through 15. + NewSegmentAppend(10, 6); // Check expected range. - CheckExpectedRanges("{ [5,13) }"); + CheckExpectedRanges("{ [5,15) }"); // Check buffers in range. Seek(5); - CheckExpectedBuffers(5, 13); + CheckExpectedBuffers(5, 15); } TEST_F(SourceBufferStreamTest, End_Overlap) { // Append 10 buffers at positions 10 through 19. - AppendBuffers(10, 10); + NewSegmentAppend(10, 10); // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10); + NewSegmentAppend(5, 10); // Check expected range. CheckExpectedRanges("{ [5,19) }"); @@ -322,10 +356,10 @@ TEST_F(SourceBufferStreamTest, End_Overlap) { TEST_F(SourceBufferStreamTest, End_Overlap_Several) { // Append 10 buffers at positions 10 through 19. - AppendBuffers(10, 10); + NewSegmentAppend(10, 10); // Append 8 buffers at positions 5 through 12. - AppendBuffers(5, 8); + NewSegmentAppend(5, 8); // Check expected ranges: stream should not have kept buffers 13 and 14 // because the keyframe on which they depended was overwritten. @@ -342,19 +376,19 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Several) { TEST_F(SourceBufferStreamTest, Complete_Overlap_Several) { // Append 2 buffers at positions 5 through 6. - AppendBuffers(5, 2); + NewSegmentAppend(5, 2); // Append 2 buffers at positions 10 through 11. - AppendBuffers(10, 2); + NewSegmentAppend(10, 2); // Append 2 buffers at positions 15 through 16. - AppendBuffers(15, 2); + NewSegmentAppend(15, 2); // Check expected ranges. CheckExpectedRanges("{ [5,6) [10,11) [15,16) }"); // Append buffers at positions 0 through 19. - AppendBuffers(0, 20); + NewSegmentAppend(0, 20); // Check expected range. CheckExpectedRanges("{ [0,19) }"); @@ -365,19 +399,19 @@ TEST_F(SourceBufferStreamTest, Complete_Overlap_Several) { TEST_F(SourceBufferStreamTest, Complete_Overlap_Several_Then_Merge) { // Append 2 buffers at positions 5 through 6. - AppendBuffers(5, 2); + NewSegmentAppend(5, 2); // Append 2 buffers at positions 10 through 11. - AppendBuffers(10, 2); + NewSegmentAppend(10, 2); // Append 2 buffers at positions 15 through 16. - AppendBuffers(15, 2); + NewSegmentAppend(15, 2); // Append 2 buffers at positions 20 through 21. - AppendBuffers(20, 2); + NewSegmentAppend(20, 2); // Append buffers at positions 0 through 19. - AppendBuffers(0, 20); + NewSegmentAppend(0, 20); // Check expected ranges. CheckExpectedRanges("{ [0,21) }"); @@ -388,13 +422,13 @@ TEST_F(SourceBufferStreamTest, Complete_Overlap_Several_Then_Merge) { TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected) { // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10, &kDataA); + NewSegmentAppend(5, 10, &kDataA); // Seek to buffer at position 5. Seek(5); // Replace old data with new data. - AppendBuffers(5, 10, &kDataB); + NewSegmentAppend(5, 10, &kDataB); // Check ranges are correct. CheckExpectedRanges("{ [5,14) }"); @@ -409,14 +443,14 @@ TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected) { // the keyframe of the new data, after which it will return the new data. TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_TrackBuffer) { // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10, &kDataA); + NewSegmentAppend(5, 10, &kDataA); // Seek to buffer at position 5 and get next buffer. Seek(5); CheckExpectedBuffers(5, 5, &kDataA); // Do a complete overlap by appending 20 buffers at positions 0 through 19. - AppendBuffers(0, 20, &kDataB); + NewSegmentAppend(0, 20, &kDataB); // Check range is correct. CheckExpectedRanges("{ [0,19) }"); @@ -438,14 +472,14 @@ TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_TrackBuffer) { TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_EdgeCase) { // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10, &kDataA); + NewSegmentAppend(5, 10, &kDataA); // Seek to buffer at position 5 and get next buffer. Seek(5); CheckExpectedBuffers(5, 5, &kDataA); // Replace existing data with new data. - AppendBuffers(5, 10, &kDataB); + NewSegmentAppend(5, 10, &kDataB); // Check ranges are correct. CheckExpectedRanges("{ [5,14) }"); @@ -470,23 +504,23 @@ TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_Multiple) { static const uint8 kDataD = 0x77; // Append 5 buffers at positions 5 through 9. - AppendBuffers(5, 5, &kDataA); + NewSegmentAppend(5, 5, &kDataA); // Seek to buffer at position 5 and get next buffer. Seek(5); CheckExpectedBuffers(5, 5, &kDataA); // Replace existing data with new data. - AppendBuffers(5, 5, &kDataB); + NewSegmentAppend(5, 5, &kDataB); // Then replace it again with different data. - AppendBuffers(5, 5, &kDataC); + NewSegmentAppend(5, 5, &kDataC); // Now append 5 new buffers at positions 10 through 14. - AppendBuffers(10, 5, &kDataC); + NewSegmentAppend(10, 5, &kDataC); // Now replace all the data entirely. - AppendBuffers(5, 10, &kDataD); + NewSegmentAppend(5, 10, &kDataD); // Expect buffers 6 through 9 to be DataA, and the remaining // buffers to be kDataD. @@ -503,11 +537,11 @@ TEST_F(SourceBufferStreamTest, Complete_Overlap_Selected_Multiple) { TEST_F(SourceBufferStreamTest, Start_Overlap_Selected) { // Append 10 buffers at positions 0 through 9. - AppendBuffers(0, 10, &kDataA); + NewSegmentAppend(0, 10, &kDataA); // Seek to position 5, then add buffers to overlap data at that position. Seek(5); - AppendBuffers(5, 10, &kDataB); + NewSegmentAppend(5, 10, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,14) }"); @@ -523,14 +557,14 @@ TEST_F(SourceBufferStreamTest, Start_Overlap_Selected) { TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_TrackBuffer) { // Append 15 buffers at positions 0 through 14. - AppendBuffers(0, 15, &kDataA); + NewSegmentAppend(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); + NewSegmentAppend(10, 10, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,19) }"); @@ -555,13 +589,13 @@ TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_TrackBuffer) { TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_EdgeCase) { // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10, &kDataA); + NewSegmentAppend(5, 10, &kDataA); Seek(10); CheckExpectedBuffers(10, 10, &kDataA); // Now replace the last 5 buffers with new data. - AppendBuffers(10, 5, &kDataB); + NewSegmentAppend(10, 5, &kDataB); // The next 4 buffers should be the origial data, held in the track buffer. CheckExpectedBuffers(11, 14, &kDataA); @@ -571,7 +605,7 @@ TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_EdgeCase) { CheckNoNextBuffer(); // Now append data at 15 through 19 and check to make sure it's correct. - AppendBuffers(15, 5, &kDataB); + NewSegmentAppend(15, 5, &kDataB); CheckExpectedBuffers(15, 19, &kDataB); // Seek to beginning of buffered range and check buffers. @@ -592,13 +626,13 @@ TEST_F(SourceBufferStreamTest, Start_Overlap_Selected_EdgeCase) { // 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); + NewSegmentAppend(5, 10, &kDataA); // Seek to position 5. Seek(5); // Now append 10 buffers at positions 0 through 9. - AppendBuffers(0, 10, &kDataB); + NewSegmentAppend(0, 10, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,14) }"); @@ -622,14 +656,14 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected) { // 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); + NewSegmentAppend(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); + NewSegmentAppend(0, 10, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,14) }"); @@ -654,14 +688,14 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_1) { // 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); + NewSegmentAppend(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); + NewSegmentAppend(0, 8, &kDataB); // Check expected ranges. CheckExpectedRanges("{ [0,7) [10,14) }"); @@ -690,14 +724,14 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_2) { // track: |a a| TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_3) { // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10, &kDataA); + NewSegmentAppend(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); + NewSegmentAppend(0, 8, &kDataB); // Check expected ranges. CheckExpectedRanges("{ [0,7) [10,14) }"); @@ -725,14 +759,14 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected_AfterEndOfNew_3) { // track: |a a| TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_1) { // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10, &kDataA); + NewSegmentAppend(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); + NewSegmentAppend(0, 10, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,14) }"); @@ -760,14 +794,14 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_1) { // 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); + NewSegmentAppend(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); + NewSegmentAppend(0, 7, &kDataB); // Check expected ranges. CheckExpectedRanges("{ [0,6) [10,14) }"); @@ -798,14 +832,14 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_2) { // 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); + NewSegmentAppend(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); + NewSegmentAppend(0, 13, &kDataB); // Check expected ranges. CheckExpectedRanges("{ [0,12) [15,19) }"); @@ -834,14 +868,14 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected_OverlappedByNew_3) { // track: |a a a a| TEST_F(SourceBufferStreamTest, End_Overlap_Selected_NoKeyframeAfterNew) { // Append 5 buffers at positions 5 through 9. - AppendBuffers(5, 5, &kDataA); + NewSegmentAppend(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); + NewSegmentAppend(0, 6, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,5) }"); @@ -868,13 +902,13 @@ TEST_F(SourceBufferStreamTest, End_Overlap_Selected_NoKeyframeAfterNew) { // 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); + NewSegmentAppend(0, 15, &kDataA); // Seek to position 5. Seek(5); // Now append 5 buffers at positions 5 through 9. - AppendBuffers(5, 5, &kDataB); + NewSegmentAppend(5, 5, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,14) }"); @@ -898,14 +932,14 @@ TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_1) { // 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); + NewSegmentAppend(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); + NewSegmentAppend(5, 5, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,14) }"); @@ -927,14 +961,14 @@ TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_2) { // 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); + NewSegmentAppend(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); + NewSegmentAppend(5, 3, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,7) [10,14) }"); @@ -956,14 +990,14 @@ TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_3) { // track: |a a| TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_4) { // Append 15 buffers at positions 0 through 14. - AppendBuffers(0, 15, &kDataA); + NewSegmentAppend(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); + NewSegmentAppend(5, 3, &kDataB); // Check expected range. CheckExpectedRanges("{ [0,7) [10,14) }"); @@ -983,7 +1017,7 @@ TEST_F(SourceBufferStreamTest, Middle_Overlap_Selected_4) { TEST_F(SourceBufferStreamTest, Seek_Keyframe) { // Append 6 buffers at positions 0 through 5. - AppendBuffers(0, 6); + NewSegmentAppend(0, 6); // Seek to beginning. Seek(0); @@ -992,7 +1026,7 @@ TEST_F(SourceBufferStreamTest, Seek_Keyframe) { TEST_F(SourceBufferStreamTest, Seek_NonKeyframe) { // Append 15 buffers at positions 0 through 14. - AppendBuffers(0, 15); + NewSegmentAppend(0, 15); // Seek to buffer at position 13. Seek(13); @@ -1015,7 +1049,7 @@ TEST_F(SourceBufferStreamTest, Seek_NotBuffered) { CheckNoNextBuffer(); // Append 2 buffers at positions 0. - AppendBuffers(0, 2); + NewSegmentAppend(0, 2); Seek(0); CheckExpectedBuffers(0, 1); @@ -1026,17 +1060,17 @@ TEST_F(SourceBufferStreamTest, Seek_NotBuffered) { TEST_F(SourceBufferStreamTest, Seek_InBetweenTimestamps) { // Append 10 buffers at positions 0 through 9. - AppendBuffers(0, 10); + NewSegmentAppend(0, 10); base::TimeDelta bump = frame_duration() / 4; CHECK(bump > base::TimeDelta()); // Seek to buffer a little after position 5. - stream_.Seek(5 * frame_duration() + bump); + stream_->Seek(5 * frame_duration() + bump); CheckExpectedBuffers(5, 5, true); // Seek to buffer a little before position 5. - stream_.Seek(5 * frame_duration() - bump); + stream_->Seek(5 * frame_duration() - bump); CheckExpectedBuffers(0, 0, true); } @@ -1046,14 +1080,14 @@ TEST_F(SourceBufferStreamTest, Seek_InBetweenTimestamps) { // response to the Seek(). TEST_F(SourceBufferStreamTest, Seek_After_TrackBuffer_Filled) { // Append 10 buffers at positions 5 through 14. - AppendBuffers(5, 10, &kDataA); + NewSegmentAppend(5, 10, &kDataA); // Seek to buffer at position 5 and get next buffer. Seek(5); CheckExpectedBuffers(5, 5, &kDataA); // Do a complete overlap by appending 20 buffers at positions 0 through 19. - AppendBuffers(0, 20, &kDataB); + NewSegmentAppend(0, 20, &kDataB); // Check range is correct. CheckExpectedRanges("{ [0,19) }"); @@ -1072,11 +1106,11 @@ TEST_F(SourceBufferStreamTest, Seek_StartOfSegment) { // Append 5 buffers at position (5 + |bump|) through 9, where the media // segment begins at position 5. - AppendBuffers(5, 5, bump); + NewSegmentAppend_OffsetFirstBuffer(5, 5, bump); scoped_refptr<StreamParserBuffer> buffer; // GetNextBuffer() should return the next buffer at position (5 + |bump|). - EXPECT_TRUE(stream_.GetNextBuffer(&buffer)); + EXPECT_TRUE(stream_->GetNextBuffer(&buffer)); EXPECT_EQ(buffer->GetDecodeTimestamp(), 5 * frame_duration() + bump); // Check rest of buffers. @@ -1087,10 +1121,10 @@ TEST_F(SourceBufferStreamTest, Seek_StartOfSegment) { // Append 5 buffers at positions (15 + |bump|) through 19, where the media // segment begins at 15. - AppendBuffers(15, 5, bump); + NewSegmentAppend_OffsetFirstBuffer(15, 5, bump); // GetNextBuffer() should return the next buffer at position (15 + |bump|). - EXPECT_TRUE(stream_.GetNextBuffer(&buffer)); + EXPECT_TRUE(stream_->GetNextBuffer(&buffer)); EXPECT_EQ(buffer->GetDecodeTimestamp(), 15 * frame_duration() + bump); // Check rest of buffers. @@ -1099,13 +1133,13 @@ TEST_F(SourceBufferStreamTest, Seek_StartOfSegment) { TEST_F(SourceBufferStreamTest, GetNextBuffer_AfterMerges) { // Append 5 buffers at positions 10 through 14. - AppendBuffers(10, 5); + NewSegmentAppend(10, 5); // Seek to buffer at position 12. Seek(12); // Append 5 buffers at positions 5 through 9. - AppendBuffers(5, 5); + NewSegmentAppend(5, 5); // Make sure ranges are merged. CheckExpectedRanges("{ [5,14) }"); @@ -1114,7 +1148,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_AfterMerges) { CheckExpectedBuffers(10, 10); // Append 5 buffers at positions 15 through 19. - AppendBuffers(15, 5); + NewSegmentAppend(15, 5); CheckExpectedRanges("{ [5,19) }"); // Make sure the remaining next buffers are correct. @@ -1123,7 +1157,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_AfterMerges) { TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenAppend) { // Append 4 buffers at positions 0 through 3. - AppendBuffers(0, 4); + NewSegmentAppend(0, 4); // Seek to buffer at position 0 and get all buffers. Seek(0); @@ -1141,7 +1175,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenAppend) { // buffer is not buffered. TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenStartOverlap) { // Append 10 buffers at positions 0 through 9 and exhaust the buffers. - AppendBuffers(0, 10, &kDataA); + NewSegmentAppend(0, 10, &kDataA); CheckExpectedBuffers(0, 9, &kDataA); // Next buffer is at position 10, so should not be able to fulfill request. @@ -1150,7 +1184,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenStartOverlap) { // Append 6 buffers at positons 5 through 10. This is to test that doing a // start-overlap successfully fulfills the read at position 10, even though // position 10 was unbuffered. - AppendBuffers(5, 6, &kDataB); + NewSegmentAppend(5, 6, &kDataB); CheckExpectedBuffers(10, 10, &kDataB); // Then add 5 buffers from positions 11 though 15. @@ -1167,9 +1201,9 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenStartOverlap) { // This test covers the case where new buffers completely overlap a range // whose next buffer is not buffered. -TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenCompeteOverlap) { +TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenCompleteOverlap) { // Append 5 buffers at positions 10 through 14 and exhaust the buffers. - AppendBuffers(10, 5, &kDataA); + NewSegmentAppend(10, 5, &kDataA); CheckExpectedBuffers(10, 14, &kDataA); // Next buffer is at position 15, so should not be able to fulfill request. @@ -1177,7 +1211,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenCompeteOverlap) { // Do a complete overlap and test that this successfully fulfills the read // at position 15. - AppendBuffers(5, 11, &kDataB); + NewSegmentAppend(5, 11, &kDataB); CheckExpectedBuffers(15, 15, &kDataB); // Then add 5 buffers from positions 16 though 20. @@ -1188,7 +1222,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenCompeteOverlap) { CheckExpectedBuffers(16, 19, &kDataB); // Do a complete overlap and replace the buffer at position 20. - AppendBuffers(0, 21, &kDataA); + NewSegmentAppend(0, 21, &kDataA); CheckExpectedBuffers(20, 20, &kDataA); } @@ -1196,7 +1230,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenCompeteOverlap) { // buffer, then an end-overlap causes the end of the range to be deleted. TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenEndOverlap) { // Append 5 buffers at positions 10 through 14 and exhaust the buffers. - AppendBuffers(10, 5, &kDataA); + NewSegmentAppend(10, 5, &kDataA); CheckExpectedBuffers(10, 14, &kDataA); CheckExpectedRanges("{ [10,14) }"); @@ -1204,7 +1238,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenEndOverlap) { CheckNoNextBuffer(); // Do an end overlap that causes the latter half of the range to be deleted. - AppendBuffers(5, 6, &kDataB); + NewSegmentAppend(5, 6, &kDataB); CheckNoNextBuffer(); CheckExpectedRanges("{ [5,10) }"); @@ -1227,14 +1261,14 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_ExhaustThenEndOverlap) { // "next buffer" position. TEST_F(SourceBufferStreamTest, GetNextBuffer_Overlap_Selected_Complete) { // Append 5 buffers at positions 5 through 9. - AppendBuffers(5, 5, &kDataA); + NewSegmentAppend(5, 5, &kDataA); // Seek to buffer at position 5 and get next buffer. Seek(5); CheckExpectedBuffers(5, 5, &kDataA); // Replace existing data with new data. - AppendBuffers(5, 5, &kDataB); + NewSegmentAppend(5, 5, &kDataB); // Expect old data up until next keyframe in new data. CheckExpectedBuffers(6, 9, &kDataA); @@ -1250,7 +1284,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_Overlap_Selected_Complete) { TEST_F(SourceBufferStreamTest, GetNextBuffer_NoSeek) { // Append 5 buffers at position 5. - AppendBuffers(5, 5); + NewSegmentAppend(5, 5); // Should receive buffers from the start without needing to seek. CheckExpectedBuffers(5, 5); @@ -1258,7 +1292,7 @@ TEST_F(SourceBufferStreamTest, GetNextBuffer_NoSeek) { TEST_F(SourceBufferStreamTest, PresentationTimestampIndependence) { // Append 20 buffers at position 0. - AppendBuffers(0, 20); + NewSegmentAppend(0, 20); int last_keyframe_idx = -1; base::TimeDelta last_keyframe_presentation_timestamp; @@ -1267,7 +1301,7 @@ TEST_F(SourceBufferStreamTest, PresentationTimestampIndependence) { // Check for IBB...BBP pattern. for (int i = 0; i < 20; i++) { scoped_refptr<StreamParserBuffer> buffer; - ASSERT_TRUE(stream_.GetNextBuffer(&buffer)); + ASSERT_TRUE(stream_->GetNextBuffer(&buffer)); if (buffer->IsKeyframe()) { EXPECT_EQ(buffer->GetTimestamp(), buffer->GetDecodeTimestamp()); @@ -1289,4 +1323,7 @@ TEST_F(SourceBufferStreamTest, PresentationTimestampIndependence) { // TODO(vrk): Add unit tests where keyframes are unaligned between streams. // (crbug.com/133557) +// TODO(vrk): Add unit tests with end of stream being called at interesting +// times. + } // namespace media diff --git a/media/webm/webm_cluster_parser.cc b/media/webm/webm_cluster_parser.cc index be5e724..c5a2fdc 100644 --- a/media/webm/webm_cluster_parser.cc +++ b/media/webm/webm_cluster_parser.cc @@ -46,8 +46,8 @@ void WebMClusterParser::Reset() { } int WebMClusterParser::Parse(const uint8* buf, int size) { - audio_.ClearBufferQueue(); - video_.ClearBufferQueue(); + audio_.Reset(); + video_.Reset(); int result = parser_.Parse(buf, size); @@ -231,84 +231,18 @@ WebMClusterParser::Track::~Track() {} bool WebMClusterParser::Track::AddBuffer( const scoped_refptr<StreamParserBuffer>& buffer) { - if (!buffers_.empty() && - buffer->GetTimestamp() == buffers_.back()->GetTimestamp()) { - DVLOG(1) << "Got a block timecode that is not strictly monotonically " - << "increasing for track " << track_num_; - return false; - } - - if (!delayed_buffers_.empty()) { - // Update the duration of the delayed buffer and place it into the queue. - scoped_refptr<StreamParserBuffer> delayed_buffer = delayed_buffers_.front(); - - // If we get another buffer with the same timestamp, put it in the delay - // queue. - if (buffer->GetTimestamp() == delayed_buffer->GetTimestamp()) { - delayed_buffers_.push_back(buffer); - - // If this buffer happens to have a duration, use it to set the - // duration on all the other buffers in the queue. - if (buffer->GetDuration() != kNoTimestamp()) - SetDelayedBufferDurations(buffer->GetDuration()); - - return true; - } - - base::TimeDelta new_duration = - buffer->GetTimestamp() - delayed_buffer->GetTimestamp(); - - if (new_duration < base::TimeDelta()) { - DVLOG(1) << "Detected out of order timestamps."; - return false; - } - - SetDelayedBufferDurations(new_duration); - } - - // Place the buffer in delayed buffer slot if we don't know - // its duration. - if (buffer->GetDuration() == kNoTimestamp()) { - delayed_buffers_.push_back(buffer); - return true; - } - - AddToBufferQueue(buffer); - return true; -} - -void WebMClusterParser::Track::Reset() { - buffers_.clear(); - delayed_buffers_.clear(); -} - -void WebMClusterParser::Track::ClearBufferQueue() { - buffers_.clear(); -} - -void WebMClusterParser::Track::SetDelayedBufferDurations( - base::TimeDelta duration) { - - for (BufferQueue::iterator itr = delayed_buffers_.begin(); - itr < delayed_buffers_.end(); ++itr) { - (*itr)->SetDuration(duration); - - AddToBufferQueue(*itr); - } - delayed_buffers_.clear(); -} - -void WebMClusterParser::Track::AddToBufferQueue( - const scoped_refptr<StreamParserBuffer>& buffer) { - DCHECK(buffer->GetDuration() > base::TimeDelta()); - - DVLOG(2) << "AddToBufferQueue() : " << track_num_ + DVLOG(2) << "AddBuffer() : " << track_num_ << " ts " << buffer->GetTimestamp().InSecondsF() << " dur " << buffer->GetDuration().InSecondsF() << " kf " << buffer->IsKeyframe() << " size " << buffer->GetDataSize(); buffers_.push_back(buffer); + return true; +} + +void WebMClusterParser::Track::Reset() { + buffers_.clear(); } } // namespace media diff --git a/media/webm/webm_cluster_parser.h b/media/webm/webm_cluster_parser.h index ea76d30..0af0361 100644 --- a/media/webm/webm_cluster_parser.h +++ b/media/webm/webm_cluster_parser.h @@ -55,21 +55,9 @@ class MEDIA_EXPORT WebMClusterParser : public WebMParserClient { // Clears all buffer state. void Reset(); - // Clears only the |buffers_|. - void ClearBufferQueue(); - private: - // Sets the duration of all the buffers in |delayed_buffers_| - // and then moves these buffers into |buffers_|. |delayed_buffers_| - // is empty when this call returns. - void SetDelayedBufferDurations(base::TimeDelta duration); - - // Adds the buffer to |buffers_|. |buffer| must have its duration set. - void AddToBufferQueue(const scoped_refptr<StreamParserBuffer>& buffer); - int track_num_; BufferQueue buffers_; - BufferQueue delayed_buffers_; }; // WebMParserClient methods. |