Index: media/filters/chunk_demuxer.cc |
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc |
index 768473c0f3ee9c8b0b79afe00887805943f48ac2..09fa2019682574b67911c5b146ec38ba316458c2 100644 |
--- a/media/filters/chunk_demuxer.cc |
+++ b/media/filters/chunk_demuxer.cc |
@@ -205,9 +205,8 @@ class ChunkDemuxerStream : public DemuxerStream { |
const LogCB& log_cb); |
virtual ~ChunkDemuxerStream(); |
- void StartWaitingForSeek(); |
+ void AbortReads(); |
void Seek(TimeDelta time); |
- void CancelPendingSeek(); |
bool IsSeekWaitingForData() const; |
// Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
@@ -245,9 +244,9 @@ class ChunkDemuxerStream : public DemuxerStream { |
private: |
enum State { |
+ UNINITIALIZED, |
RETURNING_DATA_FOR_READS, |
- WAITING_FOR_SEEK, |
- CANCELED, |
+ RETURNING_ABORT_FOR_READS, |
SHUTDOWN, |
}; |
@@ -283,23 +282,23 @@ class ChunkDemuxerStream : public DemuxerStream { |
ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
const LogCB& log_cb) |
: type_(AUDIO), |
- state_(RETURNING_DATA_FOR_READS) { |
+ state_(UNINITIALIZED) { |
stream_.reset(new SourceBufferStream(audio_config, log_cb)); |
} |
ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
const LogCB& log_cb) |
: type_(VIDEO), |
- state_(RETURNING_DATA_FOR_READS) { |
+ state_(UNINITIALIZED) { |
stream_.reset(new SourceBufferStream(video_config, log_cb)); |
} |
-void ChunkDemuxerStream::StartWaitingForSeek() { |
- DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; |
+void ChunkDemuxerStream::AbortReads() { |
+ DVLOG(1) << "ChunkDemuxerStream::AbortReads()"; |
ReadCBQueue read_cbs; |
{ |
base::AutoLock auto_lock(lock_); |
- ChangeState_Locked(WAITING_FOR_SEEK); |
+ ChangeState_Locked(RETURNING_ABORT_FOR_READS); |
std::swap(read_cbs_, read_cbs); |
} |
@@ -309,30 +308,11 @@ void ChunkDemuxerStream::StartWaitingForSeek() { |
void ChunkDemuxerStream::Seek(TimeDelta time) { |
base::AutoLock auto_lock(lock_); |
- |
DCHECK(read_cbs_.empty()); |
- |
- // Ignore seek requests when canceled. |
- if (state_ == CANCELED) |
- return; |
+ DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS); |
stream_->Seek(time); |
- |
- 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); |
+ ChangeState_Locked(RETURNING_DATA_FOR_READS); |
} |
bool ChunkDemuxerStream::IsSeekWaitingForData() const { |
@@ -449,14 +429,15 @@ static void RunOnMessageLoop( |
// DemuxerStream methods. |
void ChunkDemuxerStream::Read(const ReadCB& read_cb) { |
+ base::AutoLock auto_lock(lock_); |
+ DCHECK_NE(state_, UNINITIALIZED); |
+ |
DemuxerStream::Status status = kOk; |
scoped_refptr<StreamParserBuffer> buffer; |
- { |
- base::AutoLock auto_lock(lock_); |
- if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { |
- DeferRead_Locked(read_cb); |
- return; |
- } |
+ |
+ if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { |
+ DeferRead_Locked(read_cb); |
+ return; |
} |
base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
@@ -520,6 +501,9 @@ bool ChunkDemuxerStream::GetNextBuffer_Locked( |
lock_.AssertAcquired(); |
switch (state_) { |
+ case UNINITIALIZED: |
+ NOTREACHED(); |
+ return false; |
case RETURNING_DATA_FOR_READS: |
switch (stream_->GetNextBuffer(buffer)) { |
case SourceBufferStream::kSuccess: |
@@ -538,8 +522,7 @@ bool ChunkDemuxerStream::GetNextBuffer_Locked( |
return true; |
} |
break; |
- case CANCELED: |
- case WAITING_FOR_SEEK: |
+ case RETURNING_ABORT_FOR_READS: |
// Null buffers should be returned in this state since we are waiting |
// for a seek. Any buffers in the SourceBuffer should NOT be returned |
// because they are associated with the seek. |
@@ -563,6 +546,7 @@ ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, |
const AddTextTrackCB& add_text_track_cb, |
const LogCB& log_cb) |
: state_(WAITING_FOR_INIT), |
+ cancel_next_seek_(false), |
host_(NULL), |
open_cb_(open_cb), |
need_key_cb_(need_key_cb), |
@@ -601,28 +585,34 @@ void ChunkDemuxer::Stop(const base::Closure& callback) { |
void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { |
DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; |
DCHECK(time >= TimeDelta()); |
- DCHECK(seek_cb_.is_null()); |
- PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; |
base::AutoLock auto_lock(lock_); |
+ DCHECK(seek_cb_.is_null()); |
seek_cb_ = BindToCurrentLoop(cb); |
- if (state_ == INITIALIZED || state_ == ENDED) { |
- if (audio_) |
- audio_->Seek(time); |
+ if (state_ != INITIALIZED && state_ != ENDED) { |
+ base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_INVALID_STATE); |
+ return; |
+ } |
- if (video_) |
- video_->Seek(time); |
+ if (cancel_next_seek_) { |
+ cancel_next_seek_ = false; |
+ base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
+ return; |
+ } |
- if (IsSeekWaitingForData_Locked()) { |
- DVLOG(1) << "Seek() : waiting for more data to arrive."; |
- return; |
- } |
+ if (audio_) |
+ audio_->Seek(time); |
- 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() { |
@@ -651,29 +641,42 @@ void ChunkDemuxer::StartWaitingForSeek() { |
DVLOG(1) << "StartWaitingForSeek()"; |
base::AutoLock auto_lock(lock_); |
DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); |
+ DCHECK(seek_cb_.is_null()); |
if (state_ == SHUTDOWN) |
return; |
if (audio_) |
- audio_->StartWaitingForSeek(); |
+ audio_->AbortReads(); |
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() { |
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_) |
- audio_->CancelPendingSeek(); |
+ audio_->AbortReads(); |
if (video_) |
- video_->CancelPendingSeek(); |
+ video_->AbortReads(); |
- if (!seek_cb_.is_null()) |
- base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
+ if (seek_cb_.is_null()) { |
+ cancel_next_seek_ = true; |
+ return; |
+ } |
+ |
+ base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
} |
ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
@@ -1084,11 +1087,12 @@ void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { |
(!source_id_video_.empty() && !video_)) |
return; |
+ TimeDelta start_time = GetStartTime(); |
if (audio_) |
- audio_->Seek(TimeDelta()); |
+ audio_->Seek(start_time); |
if (video_) |
- video_->Seek(TimeDelta()); |
+ video_->Seek(start_time); |
if (duration_ == kNoTimestamp()) |
duration_ = kInfiniteDuration(); |