Index: media/filters/chunk_demuxer.cc |
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc |
index 0c27733b13c8dcbf7b7ecdc3984afafccd57a656..b98fe8e8b3a023738af25973f4417d87a4f55baa 100644 |
--- a/media/filters/chunk_demuxer.cc |
+++ b/media/filters/chunk_demuxer.cc |
@@ -30,6 +30,7 @@ class ChunkDemuxerStream : public DemuxerStream { |
virtual ~ChunkDemuxerStream(); |
void Flush(); |
+ void Seek(base::TimeDelta time); |
// Checks if it is ok to add the |buffers| to the stream. |
bool CanAddBuffers(const BufferQueue& buffers) const; |
@@ -47,15 +48,27 @@ class ChunkDemuxerStream : public DemuxerStream { |
virtual const VideoDecoderConfig& video_decoder_config(); |
private: |
+ enum State { |
+ PLAYING, |
Ami GONE FROM CHROMIUM
2012/01/28 00:19:59
Oh, also, PLAYING is a terrible name ;)
NORMAL/STE
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
Agreed. I've renamed all the states. I think they
|
+ FLUSHED, |
+ FLUSHED_END_OF_STREAM, |
Ami GONE FROM CHROMIUM
2012/01/27 23:44:58
These names are not self-explanatory as to what th
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
Done.
|
+ RECEIVED_END_OF_STREAM, |
+ END_OF_STREAM, |
+ SHUTDOWN, |
+ }; |
+ |
+ void ChangeState_Locked(State state); |
Ami GONE FROM CHROMIUM
2012/01/27 23:44:58
Commentary here and below please.
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
Done.
|
+ void DeferRead_Locked(const ReadCallback& read_cb); |
+ void CreateReadDoneClosures_Locked(std::deque<base::Closure>* closures); |
+ |
Type type_; |
AudioDecoderConfig audio_config_; |
VideoDecoderConfig video_config_; |
mutable base::Lock lock_; |
+ State state_; |
ReadCBQueue read_cbs_; |
BufferQueue buffers_; |
- bool shutdown_called_; |
- bool received_end_of_stream_; |
// Keeps track of the timestamp of the last buffer we have |
// added to |buffers_|. This is used to enforce buffers with strictly |
@@ -67,8 +80,7 @@ class ChunkDemuxerStream : public DemuxerStream { |
ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config) |
: type_(AUDIO), |
- shutdown_called_(false), |
- received_end_of_stream_(false), |
+ state_(PLAYING), |
last_buffer_timestamp_(kNoTimestamp()) { |
audio_config_.CopyFrom(audio_config); |
} |
@@ -76,8 +88,7 @@ ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config) |
ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config) |
: type_(VIDEO), |
- shutdown_called_(false), |
- received_end_of_stream_(false), |
+ state_(PLAYING), |
last_buffer_timestamp_(kNoTimestamp()) { |
video_config_.CopyFrom(video_config); |
} |
@@ -86,10 +97,42 @@ ChunkDemuxerStream::~ChunkDemuxerStream() {} |
void ChunkDemuxerStream::Flush() { |
DVLOG(1) << "Flush()"; |
+ std::deque<base::Closure> callbacks; |
Ami GONE FROM CHROMIUM
2012/01/27 23:44:58
If you changed this to:
ReadCBQueue read_cbs;
and
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
Done.
|
+ { |
+ base::AutoLock auto_lock(lock_); |
+ buffers_.clear(); |
+ ChangeState_Locked(FLUSHED); |
+ last_buffer_timestamp_ = kNoTimestamp(); |
+ |
+ // Return null to all pending Read() callbacks to indicate that |
+ // we are flushing. |
+ while(!read_cbs_.empty()) { |
+ callbacks.push_back(base::Bind(read_cbs_.front(), |
+ scoped_refptr<Buffer>())); |
+ read_cbs_.pop_front(); |
+ } |
+ } |
+ |
+ while (!callbacks.empty()) { |
+ callbacks.front().Run(); |
+ callbacks.pop_front(); |
+ } |
+} |
+ |
+void ChunkDemuxerStream::Seek(base::TimeDelta time) { |
base::AutoLock auto_lock(lock_); |
- buffers_.clear(); |
- received_end_of_stream_ = false; |
- last_buffer_timestamp_ = kNoTimestamp(); |
+ |
+ DCHECK(read_cbs_.empty()); |
+ |
+ if (state_ == FLUSHED) { |
+ ChangeState_Locked(PLAYING); |
+ return; |
+ } |
+ |
+ if (state_ == FLUSHED_END_OF_STREAM) { |
+ ChangeState_Locked(RECEIVED_END_OF_STREAM); |
+ return; |
+ } |
} |
bool ChunkDemuxerStream::CanAddBuffers(const BufferQueue& buffers) const { |
@@ -117,17 +160,15 @@ void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { |
itr != buffers.end(); itr++) { |
// Make sure we aren't trying to add a buffer after we have received and |
// "end of stream" buffer. |
- DCHECK(!received_end_of_stream_); |
+ DCHECK_NE(state_, FLUSHED_END_OF_STREAM); |
+ DCHECK_NE(state_, RECEIVED_END_OF_STREAM); |
+ DCHECK_NE(state_, END_OF_STREAM); |
if ((*itr)->IsEndOfStream()) { |
- received_end_of_stream_ = true; |
- |
- // Push enough EOS buffers to satisfy outstanding Read() requests. |
- if (read_cbs_.size() > buffers_.size()) { |
- size_t pending_read_without_data = read_cbs_.size() - buffers_.size(); |
- for (size_t i = 0; i <= pending_read_without_data; ++i) { |
- buffers_.push_back(*itr); |
- } |
+ if (state_ == FLUSHED) { |
+ ChangeState_Locked(FLUSHED_END_OF_STREAM); |
+ } else { |
+ ChangeState_Locked(RECEIVED_END_OF_STREAM); |
} |
} else { |
base::TimeDelta current_ts = (*itr)->GetTimestamp(); |
@@ -141,11 +182,7 @@ void ChunkDemuxerStream::AddBuffers(const BufferQueue& buffers) { |
} |
} |
- while (!buffers_.empty() && !read_cbs_.empty()) { |
- callbacks.push_back(base::Bind(read_cbs_.front(), buffers_.front())); |
- buffers_.pop_front(); |
- read_cbs_.pop_front(); |
- } |
+ CreateReadDoneClosures_Locked(&callbacks); |
} |
while (!callbacks.empty()) { |
@@ -158,13 +195,15 @@ void ChunkDemuxerStream::Shutdown() { |
std::deque<ReadCallback> callbacks; |
{ |
base::AutoLock auto_lock(lock_); |
- shutdown_called_ = true; |
+ ChangeState_Locked(SHUTDOWN); |
// Collect all the pending Read() callbacks. |
while (!read_cbs_.empty()) { |
Ami GONE FROM CHROMIUM
2012/01/27 23:44:58
std::swap()
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
Done.
|
callbacks.push_back(read_cbs_.front()); |
read_cbs_.pop_front(); |
} |
+ |
+ buffers_.clear(); |
} |
// Pass end of stream buffers to all callbacks to signal that no more data |
@@ -206,29 +245,41 @@ void ChunkDemuxerStream::Read(const ReadCallback& read_callback) { |
{ |
base::AutoLock auto_lock(lock_); |
- if (shutdown_called_ || (received_end_of_stream_ && buffers_.empty())) { |
- buffer = CreateEOSBuffer(); |
- } else { |
- if (buffers_.empty()) { |
- // Wrap & store |read_callback| so that it will |
- // get called on the current MessageLoop. |
- read_cbs_.push_back(base::Bind(&RunOnMessageLoop, |
- read_callback, |
- MessageLoop::current())); |
- return; |
- } |
+ switch(state_) { |
+ case PLAYING: |
+ // Satisfy the request immediately if we have a buffer and |
+ // no pending reads. |
+ if (buffers_.empty() || !read_cbs_.empty()) { |
Ami GONE FROM CHROMIUM
2012/01/27 23:44:58
This test is the opposite of the comment, which I
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
Done.
|
+ DeferRead_Locked(read_callback); |
+ return; |
+ } |
+ |
+ buffer = buffers_.front(); |
+ buffers_.pop_front(); |
+ break; |
- if (!read_cbs_.empty()) { |
- // Wrap & store |read_callback| so that it will |
- // get called on the current MessageLoop. |
- read_cbs_.push_back(base::Bind(&RunOnMessageLoop, |
- read_callback, |
- MessageLoop::current())); |
+ case FLUSHED: |
+ case FLUSHED_END_OF_STREAM: |
Ami GONE FROM CHROMIUM
2012/01/27 23:44:58
Can these not be fall-throughs to the PLAYING case
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
This was a bug. NULLs need to be immediately retur
|
+ DeferRead_Locked(read_callback); |
return; |
- } |
- buffer = buffers_.front(); |
- buffers_.pop_front(); |
+ case RECEIVED_END_OF_STREAM: |
+ DCHECK(read_cbs_.empty()); |
+ |
+ if (buffers_.empty()) { |
+ ChangeState_Locked(END_OF_STREAM); |
+ buffer = CreateEOSBuffer(); |
+ } else { |
+ buffer = buffers_.front(); |
+ buffers_.pop_front(); |
+ } |
+ break; |
+ |
+ case END_OF_STREAM: |
+ case SHUTDOWN: |
+ DCHECK(buffers_.empty()); |
+ DCHECK(read_cbs_.empty()); |
+ buffer = CreateEOSBuffer(); |
} |
} |
@@ -250,6 +301,45 @@ const VideoDecoderConfig& ChunkDemuxerStream::video_decoder_config() { |
return video_config_; |
} |
+void ChunkDemuxerStream::ChangeState_Locked(State state) { |
+ lock_.AssertAcquired(); |
+ state_ = state; |
+} |
+ |
+void ChunkDemuxerStream::DeferRead_Locked(const ReadCallback& read_cb) { |
+ lock_.AssertAcquired(); |
+ // Wrap & store |read_callback| so that it will |
+ // get called on the current MessageLoop. |
+ read_cbs_.push_back(base::Bind(&RunOnMessageLoop, read_cb, |
+ MessageLoop::current())); |
+} |
+ |
+void ChunkDemuxerStream::CreateReadDoneClosures_Locked( |
+ std::deque<base::Closure>* closures) { |
+ lock_.AssertAcquired(); |
+ |
+ while ((state_ == PLAYING || state_ == RECEIVED_END_OF_STREAM) && |
Ami GONE FROM CHROMIUM
2012/01/27 23:44:58
Having state_ in this while condition is strange (
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
Done.
|
+ !buffers_.empty() && |
+ !read_cbs_.empty()) { |
+ closures->push_back(base::Bind(read_cbs_.front(), buffers_.front())); |
+ buffers_.pop_front(); |
+ read_cbs_.pop_front(); |
+ } |
+ |
+ if (state_ == RECEIVED_END_OF_STREAM && |
+ buffers_.empty() && !read_cbs_.empty()) { |
+ |
+ // Push enough EOS buffers to satisfy outstanding Read() requests. |
+ scoped_refptr<Buffer> end_of_stream_buffer = CreateEOSBuffer(); |
+ while(!read_cbs_.empty()) { |
+ closures->push_back(base::Bind(read_cbs_.front(), end_of_stream_buffer)); |
+ read_cbs_.pop_front(); |
+ } |
+ |
+ ChangeState_Locked(END_OF_STREAM); |
+ } |
+} |
+ |
ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) |
: state_(WAITING_FOR_INIT), |
client_(client), |
@@ -306,6 +396,12 @@ void ChunkDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { |
base::AutoLock auto_lock(lock_); |
if (state_ == INITIALIZED || state_ == ENDED) { |
+ if (audio_.get()) |
Ami GONE FROM CHROMIUM
2012/01/27 23:44:58
.get() here and below are unnecessary (scoped_refp
acolwell GONE FROM CHROMIUM
2012/01/29 03:00:41
Done.
|
+ audio_->Seek(time); |
+ |
+ if (video_.get()) |
+ video_->Seek(time); |
+ |
if (seek_waits_for_data_) { |
DVLOG(1) << "Seek() : waiting for more data to arrive."; |
seek_cb_ = cb; |