Commit 2c6fef67 authored by vrk@google.com's avatar vrk@google.com

Add kSeekToStartFudgeRoom to SourceBufferStream

Consider the beginning of the buffered region to be the beginning of the stream
only if it is within the kSeekToStartFudgeFroom.

BUG=NONE

Review URL: https://chromiumcodereview.appspot.com/10832151

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150181 0039d316-1c4b-4281-b951-d872f2087c98
parent 0a6d95e9
...@@ -73,6 +73,10 @@ MATCHER_P(HasTimestamp, timestamp_in_ms, "") { ...@@ -73,6 +73,10 @@ MATCHER_P(HasTimestamp, timestamp_in_ms, "") {
arg->GetTimestamp().InMilliseconds() == timestamp_in_ms; arg->GetTimestamp().InMilliseconds() == timestamp_in_ms;
} }
MATCHER(IsEndOfStream, "") {
return arg && arg->IsEndOfStream();
}
static void OnReadDone(const base::TimeDelta& expected_time, static void OnReadDone(const base::TimeDelta& expected_time,
bool* called, bool* called,
DemuxerStream::Status status, DemuxerStream::Status status,
...@@ -586,6 +590,12 @@ class ChunkDemuxerTest : public testing::Test { ...@@ -586,6 +590,12 @@ class ChunkDemuxerTest : public testing::Test {
MOCK_METHOD2(ReadDone, void(DemuxerStream::Status status, MOCK_METHOD2(ReadDone, void(DemuxerStream::Status status,
const scoped_refptr<DecoderBuffer>&)); const scoped_refptr<DecoderBuffer>&));
void ExpectEndOfStream(DemuxerStream* stream) {
EXPECT_CALL(*this, ReadDone(DemuxerStream::kOk, IsEndOfStream()));
stream->Read(base::Bind(&ChunkDemuxerTest::ReadDone,
base::Unretained(this)));
}
void ExpectRead(DemuxerStream* stream, int64 timestamp_in_ms) { void ExpectRead(DemuxerStream* stream, int64 timestamp_in_ms) {
EXPECT_CALL(*this, ReadDone(DemuxerStream::kOk, EXPECT_CALL(*this, ReadDone(DemuxerStream::kOk,
HasTimestamp(timestamp_in_ms))); HasTimestamp(timestamp_in_ms)));
...@@ -1765,6 +1775,34 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodesSeparateSources) { ...@@ -1765,6 +1775,34 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodesSeparateSources) {
GenerateSingleStreamExpectedReads(30, 4, video, kVideoBlockDuration); GenerateSingleStreamExpectedReads(30, 4, video, kVideoBlockDuration);
} }
TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodesOutOfRange) {
std::string audio_id = "audio1";
std::string video_id = "video1";
ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
scoped_refptr<DemuxerStream> video =
demuxer_->GetStream(DemuxerStream::VIDEO);
// Generate two streams where the video stream starts 10s after the audio
// stream and append them.
scoped_ptr<Cluster> cluster_v(
GenerateSingleStreamCluster(10000, 4 * kVideoBlockDuration + 10000,
kVideoTrackNum, kVideoBlockDuration));
scoped_ptr<Cluster> cluster_a(
GenerateSingleStreamCluster(0, 4 * kAudioBlockDuration + 0,
kAudioTrackNum, kAudioBlockDuration));
ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size()));
ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size()));
// Should not be able to fulfill a seek to 0.
demuxer_->Seek(base::TimeDelta::FromMilliseconds(0),
NewExpectedStatusCB(PIPELINE_ERROR_ABORT));
ExpectRead(audio, 0);
ExpectEndOfStream(video);
}
TEST_F(ChunkDemuxerTest, TestClusterWithNoBuffers) { TEST_F(ChunkDemuxerTest, TestClusterWithNoBuffers) {
ASSERT_TRUE(InitDemuxer(true, true, false)); ASSERT_TRUE(InitDemuxer(true, true, false));
...@@ -2112,22 +2150,41 @@ TEST_F(ChunkDemuxerTest, TestTimestampOffsetSeparateStreams) { ...@@ -2112,22 +2150,41 @@ TEST_F(ChunkDemuxerTest, TestTimestampOffsetSeparateStreams) {
scoped_refptr<DemuxerStream> video = scoped_refptr<DemuxerStream> video =
demuxer_->GetStream(DemuxerStream::VIDEO); demuxer_->GetStream(DemuxerStream::VIDEO);
scoped_ptr<Cluster> cluster_a( scoped_ptr<Cluster> cluster_a1(
GenerateSingleStreamCluster( GenerateSingleStreamCluster(
2500, 2500 + kAudioBlockDuration * 4, kAudioTrackNum, 2500, 2500 + kAudioBlockDuration * 4, kAudioTrackNum,
kAudioBlockDuration)); kAudioBlockDuration));
scoped_ptr<Cluster> cluster_v( scoped_ptr<Cluster> cluster_v1(
GenerateSingleStreamCluster(
2500, 2500 + kVideoBlockDuration * 4, kVideoTrackNum,
kVideoBlockDuration));
scoped_ptr<Cluster> cluster_a2(
GenerateSingleStreamCluster(
0, kAudioBlockDuration * 4, kAudioTrackNum, kAudioBlockDuration));
scoped_ptr<Cluster> cluster_v2(
GenerateSingleStreamCluster( GenerateSingleStreamCluster(
0, kVideoBlockDuration * 4, kVideoTrackNum, kVideoBlockDuration)); 0, kVideoBlockDuration * 4, kVideoTrackNum, kVideoBlockDuration));
ASSERT_TRUE(demuxer_->SetTimestampOffset(audio_id, -2.5)); ASSERT_TRUE(demuxer_->SetTimestampOffset(audio_id, -2.5));
ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size())); ASSERT_TRUE(demuxer_->SetTimestampOffset(video_id, -2.5));
ASSERT_TRUE(AppendData(audio_id, cluster_a1->data(), cluster_a1->size()));
ASSERT_TRUE(AppendData(video_id, cluster_v1->data(), cluster_v1->size()));
GenerateSingleStreamExpectedReads(0, 4, audio, kAudioBlockDuration); GenerateSingleStreamExpectedReads(0, 4, audio, kAudioBlockDuration);
GenerateSingleStreamExpectedReads(0, 4, video, kVideoBlockDuration);
demuxer_->StartWaitingForSeek();
demuxer_->Seek(base::TimeDelta::FromMilliseconds(27300),
NewExpectedStatusCB(PIPELINE_OK));
ASSERT_TRUE(demuxer_->SetTimestampOffset(audio_id, 27.3));
ASSERT_TRUE(demuxer_->SetTimestampOffset(video_id, 27.3)); ASSERT_TRUE(demuxer_->SetTimestampOffset(video_id, 27.3));
ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size())); ASSERT_TRUE(AppendData(audio_id, cluster_a2->data(), cluster_a2->size()));
ASSERT_TRUE(AppendData(video_id, cluster_v2->data(), cluster_v2->size()));
GenerateSingleStreamExpectedReads(27300, 4, video, kVideoBlockDuration); GenerateSingleStreamExpectedReads(27300, 4, video, kVideoBlockDuration);
GenerateSingleStreamExpectedReads(27300, 4, audio, kAudioBlockDuration);
} }
TEST_F(ChunkDemuxerTest, TestTimestampOffsetMidParse) { TEST_F(ChunkDemuxerTest, TestTimestampOffsetMidParse) {
......
...@@ -231,6 +231,12 @@ static bool BufferComparator( ...@@ -231,6 +231,12 @@ static bool BufferComparator(
// is set and there's not enough information to get a better estimate. // is set and there's not enough information to get a better estimate.
static int kDefaultBufferDurationInMs = 125; static int kDefaultBufferDurationInMs = 125;
// The amount of time the beginning of the buffered data can differ from the
// start time in order to still be considered the start of stream.
static base::TimeDelta kSeekToStartFudgeRoom() {
return base::TimeDelta::FromMilliseconds(1000);
}
namespace media { namespace media {
SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config) SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config)
...@@ -388,10 +394,15 @@ bool SourceBufferStream::Append( ...@@ -388,10 +394,15 @@ bool SourceBufferStream::Append(
return true; return true;
} }
bool SourceBufferStream::IsBeforeFirstRange(base::TimeDelta timestamp) const { bool SourceBufferStream::ShouldSeekToStartOfBuffered(
base::TimeDelta seek_timestamp) const {
if (ranges_.empty()) if (ranges_.empty())
return false; return false;
return timestamp < ranges_.front()->GetStartTimestamp(); base::TimeDelta beginning_of_buffered =
ranges_.front()->GetStartTimestamp();
base::TimeDelta start_time_delta = beginning_of_buffered - stream_start_time_;
return seek_timestamp <= beginning_of_buffered &&
start_time_delta < kSeekToStartFudgeRoom();
} }
bool SourceBufferStream::IsMonotonicallyIncreasing( bool SourceBufferStream::IsMonotonicallyIncreasing(
...@@ -651,7 +662,7 @@ void SourceBufferStream::Seek(base::TimeDelta timestamp) { ...@@ -651,7 +662,7 @@ void SourceBufferStream::Seek(base::TimeDelta timestamp) {
SetSelectedRange(NULL); SetSelectedRange(NULL);
track_buffer_.clear(); track_buffer_.clear();
if (IsBeforeFirstRange(timestamp)) { if (ShouldSeekToStartOfBuffered(timestamp)) {
SetSelectedRange(ranges_.front()); SetSelectedRange(ranges_.front());
ranges_.front()->SeekToStart(); ranges_.front()->SeekToStart();
seek_pending_ = false; seek_pending_ = false;
......
...@@ -174,9 +174,9 @@ class MEDIA_EXPORT SourceBufferStream { ...@@ -174,9 +174,9 @@ class MEDIA_EXPORT SourceBufferStream {
// for the previous |selected_range_|. // for the previous |selected_range_|.
void SetSelectedRange(SourceBufferRange* range); void SetSelectedRange(SourceBufferRange* range);
// Returns true if |timestamp| occurs before the start timestamp of the first // Returns true if |seek_timestamp| refers to the beginning of the first range
// range in |ranges_|, false otherwise or if |ranges_| is empty. // in |ranges_|, false otherwise or if |ranges_| is empty.
bool IsBeforeFirstRange(base::TimeDelta timestamp) const; bool ShouldSeekToStartOfBuffered(base::TimeDelta seek_timestamp) const;
// Returns true if the timestamps of |buffers| are monotonically increasing // Returns true if the timestamps of |buffers| are monotonically increasing
// since the previous append to the media segment, false otherwise. // since the previous append to the media segment, false otherwise.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment