Commit af8b8a55 authored by acolwell@chromium.org's avatar acolwell@chromium.org

Move pending seek cancellation logic from ChunkDemuxerStream to ChunkDemuxer.

TEST=All existing unittests still pass.

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@208046 0039d316-1c4b-4281-b951-d872f2087c98
parent a22282cc
...@@ -205,9 +205,8 @@ class ChunkDemuxerStream : public DemuxerStream { ...@@ -205,9 +205,8 @@ class ChunkDemuxerStream : public DemuxerStream {
const LogCB& log_cb); const LogCB& log_cb);
virtual ~ChunkDemuxerStream(); virtual ~ChunkDemuxerStream();
void StartWaitingForSeek(); void AbortReads();
void Seek(TimeDelta time); void Seek(TimeDelta time);
void CancelPendingSeek();
bool IsSeekWaitingForData() const; bool IsSeekWaitingForData() const;
// Add buffers to this stream. Buffers are stored in SourceBufferStreams, // Add buffers to this stream. Buffers are stored in SourceBufferStreams,
...@@ -245,9 +244,9 @@ class ChunkDemuxerStream : public DemuxerStream { ...@@ -245,9 +244,9 @@ class ChunkDemuxerStream : public DemuxerStream {
private: private:
enum State { enum State {
UNINITIALIZED,
RETURNING_DATA_FOR_READS, RETURNING_DATA_FOR_READS,
WAITING_FOR_SEEK, RETURNING_ABORT_FOR_READS,
CANCELED,
SHUTDOWN, SHUTDOWN,
}; };
...@@ -283,23 +282,23 @@ class ChunkDemuxerStream : public DemuxerStream { ...@@ -283,23 +282,23 @@ class ChunkDemuxerStream : public DemuxerStream {
ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config,
const LogCB& log_cb) const LogCB& log_cb)
: type_(AUDIO), : type_(AUDIO),
state_(RETURNING_DATA_FOR_READS) { state_(UNINITIALIZED) {
stream_.reset(new SourceBufferStream(audio_config, log_cb)); stream_.reset(new SourceBufferStream(audio_config, log_cb));
} }
ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config,
const LogCB& log_cb) const LogCB& log_cb)
: type_(VIDEO), : type_(VIDEO),
state_(RETURNING_DATA_FOR_READS) { state_(UNINITIALIZED) {
stream_.reset(new SourceBufferStream(video_config, log_cb)); stream_.reset(new SourceBufferStream(video_config, log_cb));
} }
void ChunkDemuxerStream::StartWaitingForSeek() { void ChunkDemuxerStream::AbortReads() {
DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; DVLOG(1) << "ChunkDemuxerStream::AbortReads()";
ReadCBQueue read_cbs; ReadCBQueue read_cbs;
{ {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
ChangeState_Locked(WAITING_FOR_SEEK); ChangeState_Locked(RETURNING_ABORT_FOR_READS);
std::swap(read_cbs_, read_cbs); std::swap(read_cbs_, read_cbs);
} }
...@@ -309,30 +308,11 @@ void ChunkDemuxerStream::StartWaitingForSeek() { ...@@ -309,30 +308,11 @@ void ChunkDemuxerStream::StartWaitingForSeek() {
void ChunkDemuxerStream::Seek(TimeDelta time) { void ChunkDemuxerStream::Seek(TimeDelta time) {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
DCHECK(read_cbs_.empty()); DCHECK(read_cbs_.empty());
DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS);
// Ignore seek requests when canceled.
if (state_ == CANCELED)
return;
stream_->Seek(time); stream_->Seek(time);
ChangeState_Locked(RETURNING_DATA_FOR_READS);
if (state_ == WAITING_FOR_SEEK)
ChangeState_Locked(RETURNING_DATA_FOR_READS);
}
void ChunkDemuxerStream::CancelPendingSeek() {
DVLOG(1) << "ChunkDemuxerStream::CancelPendingSeek()";
ReadCBQueue read_cbs;
{
base::AutoLock auto_lock(lock_);
ChangeState_Locked(CANCELED);
std::swap(read_cbs_, read_cbs);
}
for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it)
it->Run(kAborted, NULL);
} }
bool ChunkDemuxerStream::IsSeekWaitingForData() const { bool ChunkDemuxerStream::IsSeekWaitingForData() const {
...@@ -449,14 +429,15 @@ static void RunOnMessageLoop( ...@@ -449,14 +429,15 @@ static void RunOnMessageLoop(
// DemuxerStream methods. // DemuxerStream methods.
void ChunkDemuxerStream::Read(const ReadCB& read_cb) { void ChunkDemuxerStream::Read(const ReadCB& read_cb) {
base::AutoLock auto_lock(lock_);
DCHECK_NE(state_, UNINITIALIZED);
DemuxerStream::Status status = kOk; DemuxerStream::Status status = kOk;
scoped_refptr<StreamParserBuffer> buffer; scoped_refptr<StreamParserBuffer> buffer;
{
base::AutoLock auto_lock(lock_); if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) {
if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { DeferRead_Locked(read_cb);
DeferRead_Locked(read_cb); return;
return;
}
} }
base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind(
...@@ -520,6 +501,9 @@ bool ChunkDemuxerStream::GetNextBuffer_Locked( ...@@ -520,6 +501,9 @@ bool ChunkDemuxerStream::GetNextBuffer_Locked(
lock_.AssertAcquired(); lock_.AssertAcquired();
switch (state_) { switch (state_) {
case UNINITIALIZED:
NOTREACHED();
return false;
case RETURNING_DATA_FOR_READS: case RETURNING_DATA_FOR_READS:
switch (stream_->GetNextBuffer(buffer)) { switch (stream_->GetNextBuffer(buffer)) {
case SourceBufferStream::kSuccess: case SourceBufferStream::kSuccess:
...@@ -538,8 +522,7 @@ bool ChunkDemuxerStream::GetNextBuffer_Locked( ...@@ -538,8 +522,7 @@ bool ChunkDemuxerStream::GetNextBuffer_Locked(
return true; return true;
} }
break; break;
case CANCELED: case RETURNING_ABORT_FOR_READS:
case WAITING_FOR_SEEK:
// Null buffers should be returned in this state since we are waiting // Null buffers should be returned in this state since we are waiting
// for a seek. Any buffers in the SourceBuffer should NOT be returned // for a seek. Any buffers in the SourceBuffer should NOT be returned
// because they are associated with the seek. // because they are associated with the seek.
...@@ -563,6 +546,7 @@ ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, ...@@ -563,6 +546,7 @@ ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb,
const AddTextTrackCB& add_text_track_cb, const AddTextTrackCB& add_text_track_cb,
const LogCB& log_cb) const LogCB& log_cb)
: state_(WAITING_FOR_INIT), : state_(WAITING_FOR_INIT),
cancel_next_seek_(false),
host_(NULL), host_(NULL),
open_cb_(open_cb), open_cb_(open_cb),
need_key_cb_(need_key_cb), need_key_cb_(need_key_cb),
...@@ -601,28 +585,34 @@ void ChunkDemuxer::Stop(const base::Closure& callback) { ...@@ -601,28 +585,34 @@ void ChunkDemuxer::Stop(const base::Closure& callback) {
void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) {
DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
DCHECK(time >= TimeDelta()); DCHECK(time >= TimeDelta());
DCHECK(seek_cb_.is_null());
PipelineStatus status = PIPELINE_ERROR_INVALID_STATE;
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
DCHECK(seek_cb_.is_null());
seek_cb_ = BindToCurrentLoop(cb); seek_cb_ = BindToCurrentLoop(cb);
if (state_ == INITIALIZED || state_ == ENDED) { if (state_ != INITIALIZED && state_ != ENDED) {
if (audio_) base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_INVALID_STATE);
audio_->Seek(time); return;
}
if (video_) if (cancel_next_seek_) {
video_->Seek(time); cancel_next_seek_ = false;
base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
return;
}
if (IsSeekWaitingForData_Locked()) { if (audio_)
DVLOG(1) << "Seek() : waiting for more data to arrive."; audio_->Seek(time);
return;
}
status = PIPELINE_OK; if (video_)
video_->Seek(time);
if (IsSeekWaitingForData_Locked()) {
DVLOG(1) << "Seek() : waiting for more data to arrive.";
return;
} }
base::ResetAndReturn(&seek_cb_).Run(status); base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
} }
void ChunkDemuxer::OnAudioRendererDisabled() { void ChunkDemuxer::OnAudioRendererDisabled() {
...@@ -651,29 +641,42 @@ void ChunkDemuxer::StartWaitingForSeek() { ...@@ -651,29 +641,42 @@ void ChunkDemuxer::StartWaitingForSeek() {
DVLOG(1) << "StartWaitingForSeek()"; DVLOG(1) << "StartWaitingForSeek()";
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN);
DCHECK(seek_cb_.is_null());
if (state_ == SHUTDOWN) if (state_ == SHUTDOWN)
return; return;
if (audio_) if (audio_)
audio_->StartWaitingForSeek(); audio_->AbortReads();
if (video_) if (video_)
video_->StartWaitingForSeek(); video_->AbortReads();
// Cancel state set in CancelPendingSeek() since we want to
// accept the next Seek().
cancel_next_seek_ = false;
} }
void ChunkDemuxer::CancelPendingSeek() { void ChunkDemuxer::CancelPendingSeek() {
base::AutoLock auto_lock(lock_); base::AutoLock auto_lock(lock_);
DCHECK(seek_cb_.is_null() != IsSeekWaitingForData_Locked()); DCHECK_NE(state_, INITIALIZING);
DCHECK(seek_cb_.is_null() || IsSeekWaitingForData_Locked());
if (cancel_next_seek_)
return;
if (audio_) if (audio_)
audio_->CancelPendingSeek(); audio_->AbortReads();
if (video_) if (video_)
video_->CancelPendingSeek(); video_->AbortReads();
if (!seek_cb_.is_null()) if (seek_cb_.is_null()) {
base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); cancel_next_seek_ = true;
return;
}
base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK);
} }
ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
...@@ -1084,11 +1087,12 @@ void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { ...@@ -1084,11 +1087,12 @@ void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) {
(!source_id_video_.empty() && !video_)) (!source_id_video_.empty() && !video_))
return; return;
TimeDelta start_time = GetStartTime();
if (audio_) if (audio_)
audio_->Seek(TimeDelta()); audio_->Seek(start_time);
if (video_) if (video_)
video_->Seek(TimeDelta()); video_->Seek(start_time);
if (duration_ == kNoTimestamp()) if (duration_ == kNoTimestamp())
duration_ = kInfiniteDuration(); duration_ = kInfiniteDuration();
......
...@@ -62,7 +62,22 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { ...@@ -62,7 +62,22 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
virtual base::TimeDelta GetStartTime() const OVERRIDE; virtual base::TimeDelta GetStartTime() const OVERRIDE;
// Methods used by an external object to control this demuxer. // Methods used by an external object to control this demuxer.
//
// Indicates that a new Seek() call is on its way. Any pending Reads on the
// DemuxerStream objects should be aborted immediately inside this call and
// future Read calls should return kAborted until the Seek() call occurs.
// This method MUST ALWAYS be called before Seek() is called to signal that
// the next Seek() call represents the seek point we actually want to return
// data for.
void StartWaitingForSeek(); void StartWaitingForSeek();
// Indicates that a Seek() call is on its way, but another seek has been
// requested that will override the impending Seek() call. Any pending Reads
// on the DemuxerStream objects should be aborted immediately inside this call
// and future Read calls should return kAborted until the next
// StartWaitingForSeek() call. This method also arranges for the next Seek()
// call received before a StartWaitingForSeek() call to immediately call its
// callback without waiting for any data.
void CancelPendingSeek(); void CancelPendingSeek();
// Registers a new |id| to use for AppendData() calls. |type| indicates // Registers a new |id| to use for AppendData() calls. |type| indicates
...@@ -176,6 +191,7 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { ...@@ -176,6 +191,7 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
mutable base::Lock lock_; mutable base::Lock lock_;
State state_; State state_;
bool cancel_next_seek_;
DemuxerHost* host_; DemuxerHost* host_;
base::Closure open_cb_; base::Closure open_cb_;
......
...@@ -790,6 +790,12 @@ class ChunkDemuxerTest : public testing::Test { ...@@ -790,6 +790,12 @@ class ChunkDemuxerTest : public testing::Test {
return scoped_ptr<TextTrack>(); return scoped_ptr<TextTrack>();
} }
void Seek(base::TimeDelta seek_time) {
demuxer_->StartWaitingForSeek();
demuxer_->Seek(seek_time, NewExpectedStatusCB(PIPELINE_OK));
message_loop_.RunUntilIdle();
}
base::MessageLoop message_loop_; base::MessageLoop message_loop_;
MockDemuxerHost host_; MockDemuxerHost host_;
...@@ -884,8 +890,7 @@ TEST_F(ChunkDemuxerTest, TestAppendDataAfterSeek) { ...@@ -884,8 +890,7 @@ TEST_F(ChunkDemuxerTest, TestAppendDataAfterSeek) {
EXPECT_CALL(*this, Checkpoint(1)); EXPECT_CALL(*this, Checkpoint(1));
demuxer_->Seek(base::TimeDelta::FromMilliseconds(46), Seek(base::TimeDelta::FromMilliseconds(46));
NewExpectedStatusCB(PIPELINE_OK));
EXPECT_CALL(*this, Checkpoint(2)); EXPECT_CALL(*this, Checkpoint(2));
...@@ -935,9 +940,7 @@ TEST_F(ChunkDemuxerTest, TestSeekWhileParsingCluster) { ...@@ -935,9 +940,7 @@ TEST_F(ChunkDemuxerTest, TestSeekWhileParsingCluster) {
// in the cluster the cluster. // in the cluster the cluster.
ExpectRead(DemuxerStream::AUDIO, 2 * kAudioBlockDuration); ExpectRead(DemuxerStream::AUDIO, 2 * kAudioBlockDuration);
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromSeconds(5));
demuxer_->Seek(base::TimeDelta::FromSeconds(5),
NewExpectedStatusCB(PIPELINE_OK));
// Append the rest of the cluster. // Append the rest of the cluster.
AppendData(cluster_a->data() + first_append_size, second_append_size); AppendData(cluster_a->data() + first_append_size, second_append_size);
...@@ -1268,20 +1271,14 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamDuringCanceledSeek) { ...@@ -1268,20 +1271,14 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamDuringCanceledSeek) {
demuxer_->EndOfStream(PIPELINE_OK); demuxer_->EndOfStream(PIPELINE_OK);
// Start the first seek. // Start the first seek.
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromMilliseconds(20));
// Simulate the pipeline finally calling Seek().
demuxer_->Seek(base::TimeDelta::FromMilliseconds(20),
NewExpectedStatusCB(PIPELINE_OK));
// Simulate another seek being requested before the first // Simulate another seek being requested before the first
// seek has finished prerolling. // seek has finished prerolling.
demuxer_->CancelPendingSeek(); demuxer_->CancelPendingSeek();
// Finish second seek. // Finish second seek.
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromMilliseconds(30));
demuxer_->Seek(base::TimeDelta::FromMilliseconds(30),
NewExpectedStatusCB(PIPELINE_OK));
DemuxerStream::Status status; DemuxerStream::Status status;
base::TimeDelta last_timestamp; base::TimeDelta last_timestamp;
...@@ -1601,9 +1598,7 @@ TEST_F(ChunkDemuxerTest, TestSeekCanceled) { ...@@ -1601,9 +1598,7 @@ TEST_F(ChunkDemuxerTest, TestSeekCanceled) {
AppendData(start_cluster->data(), start_cluster->size()); AppendData(start_cluster->data(), start_cluster->size());
// Seek to an unbuffered region. // Seek to an unbuffered region.
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromSeconds(50));
demuxer_->Seek(base::TimeDelta::FromSeconds(50),
NewExpectedStatusCB(PIPELINE_OK));
// Attempt to read in unbuffered area; should not fulfill the read. // Attempt to read in unbuffered area; should not fulfill the read.
bool audio_read_done = false; bool audio_read_done = false;
...@@ -1620,9 +1615,7 @@ TEST_F(ChunkDemuxerTest, TestSeekCanceled) { ...@@ -1620,9 +1615,7 @@ TEST_F(ChunkDemuxerTest, TestSeekCanceled) {
EXPECT_TRUE(video_read_done); EXPECT_TRUE(video_read_done);
// A seek back to the buffered region should succeed. // A seek back to the buffered region should succeed.
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromSeconds(0));
demuxer_->Seek(base::TimeDelta::FromSeconds(0),
NewExpectedStatusCB(PIPELINE_OK));
GenerateExpectedReads(0, 4); GenerateExpectedReads(0, 4);
} }
...@@ -1650,9 +1643,7 @@ TEST_F(ChunkDemuxerTest, TestSeekCanceledWhileWaitingForSeek) { ...@@ -1650,9 +1643,7 @@ TEST_F(ChunkDemuxerTest, TestSeekCanceledWhileWaitingForSeek) {
EXPECT_TRUE(video_read_done); EXPECT_TRUE(video_read_done);
// A seek back to the buffered region should succeed. // A seek back to the buffered region should succeed.
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromSeconds(0));
demuxer_->Seek(base::TimeDelta::FromSeconds(0),
NewExpectedStatusCB(PIPELINE_OK));
GenerateExpectedReads(0, 4); GenerateExpectedReads(0, 4);
} }
...@@ -1684,9 +1675,7 @@ TEST_F(ChunkDemuxerTest, TestSeekAudioAndVideoSources) { ...@@ -1684,9 +1675,7 @@ TEST_F(ChunkDemuxerTest, TestSeekAudioAndVideoSources) {
EXPECT_TRUE(video_read_done); EXPECT_TRUE(video_read_done);
// Seek to 3 (an unbuffered region). // Seek to 3 (an unbuffered region).
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromSeconds(3));
demuxer_->Seek(base::TimeDelta::FromSeconds(3),
NewExpectedStatusCB(PIPELINE_OK));
audio_read_done = false; audio_read_done = false;
video_read_done = false; video_read_done = false;
...@@ -1971,14 +1960,11 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodes) { ...@@ -1971,14 +1960,11 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodes) {
scoped_ptr<Cluster> start_cluster(GenerateCluster(0, 25, 8)); scoped_ptr<Cluster> start_cluster(GenerateCluster(0, 25, 8));
AppendData(start_cluster->data(), start_cluster->size()); AppendData(start_cluster->data(), start_cluster->size());
demuxer_->Seek(base::TimeDelta::FromSeconds(0), Seek(base::TimeDelta::FromSeconds(0));
NewExpectedStatusCB(PIPELINE_OK));
GenerateExpectedReads(0, 25, 8); GenerateExpectedReads(0, 25, 8);
// Seek to 5 seconds. // Seek to 5 seconds.
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromSeconds(5));
demuxer_->Seek(base::TimeDelta::FromSeconds(5),
NewExpectedStatusCB(PIPELINE_OK));
// Generate a cluster to fulfill this seek, where audio timecode begins 25ms // Generate a cluster to fulfill this seek, where audio timecode begins 25ms
// after the video. // after the video.
...@@ -2004,8 +1990,7 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodesSeparateSources) { ...@@ -2004,8 +1990,7 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodesSeparateSources) {
AppendData(video_id, cluster_v->data(), cluster_v->size()); AppendData(video_id, cluster_v->data(), cluster_v->size());
// Both streams should be able to fulfill a seek to 25. // Both streams should be able to fulfill a seek to 25.
demuxer_->Seek(base::TimeDelta::FromMilliseconds(25), Seek(base::TimeDelta::FromMilliseconds(25));
NewExpectedStatusCB(PIPELINE_OK));
GenerateAudioStreamExpectedReads(25, 4); GenerateAudioStreamExpectedReads(25, 4);
GenerateVideoStreamExpectedReads(30, 4); GenerateVideoStreamExpectedReads(30, 4);
} }
...@@ -2027,6 +2012,7 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodesOutOfRange) { ...@@ -2027,6 +2012,7 @@ TEST_F(ChunkDemuxerTest, TestDifferentStreamTimecodesOutOfRange) {
AppendData(video_id, cluster_v->data(), cluster_v->size()); AppendData(video_id, cluster_v->data(), cluster_v->size());
// Should not be able to fulfill a seek to 0. // Should not be able to fulfill a seek to 0.
demuxer_->StartWaitingForSeek();
demuxer_->Seek(base::TimeDelta::FromMilliseconds(0), demuxer_->Seek(base::TimeDelta::FromMilliseconds(0),
NewExpectedStatusCB(PIPELINE_ERROR_ABORT)); NewExpectedStatusCB(PIPELINE_ERROR_ABORT));
ExpectRead(DemuxerStream::AUDIO, 0); ExpectRead(DemuxerStream::AUDIO, 0);
...@@ -2116,9 +2102,7 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamStillSetAfterSeek) { ...@@ -2116,9 +2102,7 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamStillSetAfterSeek) {
EXPECT_EQ(kLastVideoTimestamp, last_timestamp); EXPECT_EQ(kLastVideoTimestamp, last_timestamp);
// Seek back to 0 and verify that we can read to the end again.. // Seek back to 0 and verify that we can read to the end again..
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromMilliseconds(0));
demuxer_->Seek(base::TimeDelta::FromMilliseconds(0),
NewExpectedStatusCB(PIPELINE_OK));
ReadUntilNotOkOrEndOfStream(DemuxerStream::AUDIO, &status, &last_timestamp); ReadUntilNotOkOrEndOfStream(DemuxerStream::AUDIO, &status, &last_timestamp);
EXPECT_EQ(DemuxerStream::kOk, status); EXPECT_EQ(DemuxerStream::kOk, status);
...@@ -2278,8 +2262,7 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Seek) { ...@@ -2278,8 +2262,7 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Seek) {
ExpectRead(DemuxerStream::VIDEO, 0); ExpectRead(DemuxerStream::VIDEO, 0);
// Seek to a location with a different config. // Seek to a location with a different config.
demuxer_->Seek(base::TimeDelta::FromMilliseconds(527), Seek(base::TimeDelta::FromMilliseconds(527));
NewExpectedStatusCB(PIPELINE_OK));
// Verify that the config change is signalled. // Verify that the config change is signalled.
ExpectConfigChanged(DemuxerStream::VIDEO); ExpectConfigChanged(DemuxerStream::VIDEO);
...@@ -2294,8 +2277,7 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Seek) { ...@@ -2294,8 +2277,7 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Seek) {
ExpectRead(DemuxerStream::VIDEO, 527); ExpectRead(DemuxerStream::VIDEO, 527);
// Seek back to the beginning and verify we get another config change. // Seek back to the beginning and verify we get another config change.
demuxer_->Seek(base::TimeDelta::FromMilliseconds(0), Seek(base::TimeDelta::FromMilliseconds(0));
NewExpectedStatusCB(PIPELINE_OK));
ExpectConfigChanged(DemuxerStream::VIDEO); ExpectConfigChanged(DemuxerStream::VIDEO);
ASSERT_TRUE(video_config_1.Matches(video->video_decoder_config())); ASSERT_TRUE(video_config_1.Matches(video->video_decoder_config()));
ExpectRead(DemuxerStream::VIDEO, 0); ExpectRead(DemuxerStream::VIDEO, 0);
...@@ -2303,10 +2285,8 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Seek) { ...@@ -2303,10 +2285,8 @@ TEST_F(ChunkDemuxerTest, TestConfigChange_Seek) {
// Seek to a location that requires a config change and then // Seek to a location that requires a config change and then
// seek to a new location that has the same configuration as // seek to a new location that has the same configuration as
// the start of the file without a Read() in the middle. // the start of the file without a Read() in the middle.
demuxer_->Seek(base::TimeDelta::FromMilliseconds(527), Seek(base::TimeDelta::FromMilliseconds(527));
NewExpectedStatusCB(PIPELINE_OK)); Seek(base::TimeDelta::FromMilliseconds(801));
demuxer_->Seek(base::TimeDelta::FromMilliseconds(801),
NewExpectedStatusCB(PIPELINE_OK));
// Verify that no config change is signalled. // Verify that no config change is signalled.
ExpectRead(DemuxerStream::VIDEO, 801); ExpectRead(DemuxerStream::VIDEO, 801);
...@@ -2321,9 +2301,7 @@ TEST_F(ChunkDemuxerTest, TestTimestampPositiveOffset) { ...@@ -2321,9 +2301,7 @@ TEST_F(ChunkDemuxerTest, TestTimestampPositiveOffset) {
scoped_ptr<Cluster> cluster(GenerateCluster(0, 2)); scoped_ptr<Cluster> cluster(GenerateCluster(0, 2));
AppendData(cluster->data(), cluster->size()); AppendData(cluster->data(), cluster->size());
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromMilliseconds(30000));
demuxer_->Seek(base::TimeDelta::FromMilliseconds(30000),
NewExpectedStatusCB(PIPELINE_OK));
GenerateExpectedReads(30000, 2); GenerateExpectedReads(30000, 2);
} }
...@@ -2371,9 +2349,7 @@ TEST_F(ChunkDemuxerTest, TestTimestampOffsetSeparateStreams) { ...@@ -2371,9 +2349,7 @@ TEST_F(ChunkDemuxerTest, TestTimestampOffsetSeparateStreams) {
GenerateAudioStreamExpectedReads(0, 4); GenerateAudioStreamExpectedReads(0, 4);
GenerateVideoStreamExpectedReads(0, 4); GenerateVideoStreamExpectedReads(0, 4);
demuxer_->StartWaitingForSeek(); Seek(base::TimeDelta::FromMilliseconds(27300));
demuxer_->Seek(base::TimeDelta::FromMilliseconds(27300),
NewExpectedStatusCB(PIPELINE_OK));
ASSERT_TRUE(demuxer_->SetTimestampOffset( ASSERT_TRUE(demuxer_->SetTimestampOffset(
audio_id, base::TimeDelta::FromMilliseconds(27300))); audio_id, base::TimeDelta::FromMilliseconds(27300)));
...@@ -2573,4 +2549,18 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamWhileWaitingForGapToBeFilled) { ...@@ -2573,4 +2549,18 @@ TEST_F(ChunkDemuxerTest, TestEndOfStreamWhileWaitingForGapToBeFilled) {
EXPECT_TRUE(video_read_done); EXPECT_TRUE(video_read_done);
} }
TEST_F(ChunkDemuxerTest, TestCanceledSeekDuringInitialPreroll) {
ASSERT_TRUE(InitDemuxer(true, true));
// Cancel preroll.
demuxer_->CancelPendingSeek();
// Initiate the seek to the new location.
int seek_time_in_ms = 200;
Seek(base::TimeDelta::FromMilliseconds(seek_time_in_ms));
// Append data to satisfy the seek.
AppendCluster(seek_time_in_ms, 10);
}
} // namespace media } // namespace media
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