Index: media/filters/chunk_demuxer.cc |
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc |
index fdd47e7fcf8cb4f2e3871fb82b03658d519bec51..cc086af4c5f4b04eb49306b212665c1d5f116ecb 100644 |
--- a/media/filters/chunk_demuxer.cc |
+++ b/media/filters/chunk_demuxer.cc |
@@ -21,6 +21,147 @@ using base::TimeDelta; |
namespace media { |
+// Contains state belonging to a source id. |
+class SourceState { |
scherkus (not reviewing)
2013/04/05 18:58:26
does it make any sense to split this class out + u
acolwell GONE FROM CHROMIUM
2013/04/05 19:14:37
I'm not sure it quite makes sense yet. I think Chu
|
+ public: |
+ explicit SourceState(scoped_ptr<StreamParser> stream_parser); |
+ |
+ void Init(const StreamParser::InitCB& init_cb, |
+ const StreamParser::NewConfigCB& config_cb, |
+ const StreamParser::NewBuffersCB& audio_cb, |
+ const StreamParser::NewBuffersCB& video_cb, |
+ const StreamParser::NeedKeyCB& need_key_cb, |
+ const StreamParser::NewMediaSegmentCB& new_segment_cb, |
+ const LogCB& log_cb); |
+ |
+ // Appends new data to the StreamParser. |
+ // Returns true if the data was successfully appended. Returns false if an |
+ // error occurred. |
+ bool Append(const uint8* data, size_t length); |
+ |
+ // Aborts the current append sequence and resets the parser. |
+ void Abort(); |
+ |
+ // Sets |timestamp_offset_| if possible. |
+ // Returns if the offset was set. Returns false if the offset could not be |
+ // updated at this time. |
+ bool SetTimestampOffset(TimeDelta timestamp_offset); |
+ |
+ TimeDelta timestamp_offset() const { return timestamp_offset_; } |
+ |
+ private: |
+ // Called by the |stream_parser_| at the beginning of a new media segment. |
+ // |timestamp| is the timestamp on the first buffer in the segment. |
+ // It modifies the state of this object and then calls |new_segment_cb| with |
+ // modified version of |timestamp|. |
+ void OnNewMediaSegment(const StreamParser::NewMediaSegmentCB& new_segment_cb, |
+ TimeDelta timestamp); |
+ |
+ // Called by the |stream_parser_| at the end of a media segment. |
+ void OnEndOfMediaSegment(); |
+ |
+ // Called by the |stream_parser_| when new buffers have been parsed. It |
+ // applies |timestamp_offset_| to all buffers in |buffers| and then calls |
+ // |new_buffers_cb| with the modified buffers. |
+ // Returns true on a successful call. Returns false if an error occured while |
+ // processing the buffers. |
+ bool OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, |
+ const StreamParser::BufferQueue& buffers); |
+ |
+ // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. |
+ void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); |
+ |
+ // The offset to apply to media segment timestamps. |
+ TimeDelta timestamp_offset_; |
+ |
+ // Keeps track of whether |timestamp_offset_| can be modified. |
+ bool can_update_offset_; |
+ |
+ // The object used to parse appended data. |
+ scoped_ptr<StreamParser> stream_parser_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SourceState); |
+}; |
+ |
+SourceState::SourceState(scoped_ptr<StreamParser> stream_parser) |
+ : can_update_offset_(true), |
+ stream_parser_(stream_parser.release()) { |
+} |
+ |
+void SourceState::Init(const StreamParser::InitCB& init_cb, |
+ const StreamParser::NewConfigCB& config_cb, |
+ const StreamParser::NewBuffersCB& audio_cb, |
+ const StreamParser::NewBuffersCB& video_cb, |
+ const StreamParser::NeedKeyCB& need_key_cb, |
+ const StreamParser::NewMediaSegmentCB& new_segment_cb, |
+ const LogCB& log_cb) { |
+ stream_parser_->Init(init_cb, config_cb, |
+ base::Bind(&SourceState::OnBuffers, |
+ base::Unretained(this), audio_cb), |
+ base::Bind(&SourceState::OnBuffers, |
+ base::Unretained(this), video_cb), |
+ need_key_cb, |
+ base::Bind(&SourceState::OnNewMediaSegment, |
+ base::Unretained(this), new_segment_cb), |
+ base::Bind(&SourceState::OnEndOfMediaSegment, |
+ base::Unretained(this)), |
+ log_cb); |
+} |
+ |
+bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { |
+ if (!can_update_offset_) |
+ return false; |
+ |
+ timestamp_offset_ = timestamp_offset; |
+ return true; |
+} |
+ |
+bool SourceState::Append(const uint8* data, size_t length) { |
+ return stream_parser_->Parse(data, length); |
+} |
+ |
+void SourceState::Abort() { |
+ stream_parser_->Flush(); |
+ can_update_offset_ = true; |
+} |
+ |
+void SourceState::AdjustBufferTimestamps( |
+ const StreamParser::BufferQueue& buffers) { |
+ if (timestamp_offset_ == TimeDelta()) |
+ return; |
+ |
+ for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
+ itr != buffers.end(); ++itr) { |
+ (*itr)->SetDecodeTimestamp( |
+ (*itr)->GetDecodeTimestamp() + timestamp_offset_); |
+ (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset_); |
+ } |
+} |
+ |
+void SourceState::OnNewMediaSegment( |
+ const StreamParser::NewMediaSegmentCB& new_segment_cb, |
+ TimeDelta timestamp) { |
+ DCHECK(timestamp != kNoTimestamp()); |
+ DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")"; |
+ |
+ can_update_offset_ = false; |
+ new_segment_cb.Run(timestamp + timestamp_offset_); |
+} |
+ |
+void SourceState::OnEndOfMediaSegment() { |
+ DVLOG(2) << "OnEndOfMediaSegment()"; |
+ can_update_offset_ = true; |
+} |
+ |
+bool SourceState::OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, |
+ const StreamParser::BufferQueue& buffers) { |
+ if (new_buffers_cb.is_null()) |
+ return false; |
+ |
+ AdjustBufferTimestamps(buffers); |
+ |
+ return new_buffers_cb.Run(buffers); |
+} |
class ChunkDemuxerStream : public DemuxerStream { |
public: |
@@ -533,8 +674,7 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
DCHECK_GT(codecs.size(), 0u); |
base::AutoLock auto_lock(lock_); |
- if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || |
- stream_parser_map_.count(id) > 0u) |
+ if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) |
return kReachedIdLimit; |
bool has_audio = false; |
@@ -565,22 +705,18 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
base::Unretained(this)); |
} |
- stream_parser->Init( |
- base::Bind(&ChunkDemuxer::OnStreamParserInitDone, base::Unretained(this)), |
+ scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); |
+ source_state->Init( |
+ base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), |
base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), |
has_audio, has_video), |
audio_cb, |
video_cb, |
base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), |
base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), |
- base::Bind(&ChunkDemuxer::OnEndOfMediaSegment, |
- base::Unretained(this), id), |
log_cb_); |
- stream_parser_map_[id] = stream_parser.release(); |
- SourceInfo info = { base::TimeDelta(), true }; |
- source_info_map_[id] = info; |
- |
+ source_state_map_[id] = source_state.release(); |
return kOk; |
} |
@@ -588,9 +724,8 @@ void ChunkDemuxer::RemoveId(const std::string& id) { |
base::AutoLock auto_lock(lock_); |
CHECK(IsValidId(id)); |
- delete stream_parser_map_[id]; |
- stream_parser_map_.erase(id); |
- source_info_map_.erase(id); |
+ delete source_state_map_[id]; |
+ source_state_map_.erase(id); |
if (source_id_audio_ == id) { |
if (audio_) |
@@ -689,7 +824,7 @@ void ChunkDemuxer::AppendData(const std::string& id, |
switch (state_) { |
case INITIALIZING: |
DCHECK(IsValidId(id)); |
- if (!stream_parser_map_[id]->Parse(data, length)) { |
+ if (!source_state_map_[id]->Append(data, length)) { |
ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
return; |
} |
@@ -697,7 +832,7 @@ void ChunkDemuxer::AppendData(const std::string& id, |
case INITIALIZED: { |
DCHECK(IsValidId(id)); |
- if (!stream_parser_map_[id]->Parse(data, length)) { |
+ if (!source_state_map_[id]->Append(data, length)) { |
ReportError_Locked(PIPELINE_ERROR_DECODE); |
return; |
} |
@@ -735,8 +870,7 @@ void ChunkDemuxer::Abort(const std::string& id) { |
base::AutoLock auto_lock(lock_); |
DCHECK(!id.empty()); |
CHECK(IsValidId(id)); |
- stream_parser_map_[id]->Flush(); |
- source_info_map_[id].can_update_offset = true; |
+ source_state_map_[id]->Abort(); |
} |
double ChunkDemuxer::GetDuration() { |
@@ -807,11 +941,7 @@ bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { |
DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")"; |
CHECK(IsValidId(id)); |
- if (!source_info_map_[id].can_update_offset) |
- return false; |
- |
- source_info_map_[id].timestamp_offset = offset; |
- return true; |
+ return source_state_map_[id]->SetTimestampOffset(offset); |
} |
bool ChunkDemuxer::EndOfStream(PipelineStatus status) { |
@@ -880,11 +1010,11 @@ void ChunkDemuxer::ChangeState_Locked(State new_state) { |
ChunkDemuxer::~ChunkDemuxer() { |
DCHECK_NE(state_, INITIALIZED); |
- for (StreamParserMap::iterator it = stream_parser_map_.begin(); |
- it != stream_parser_map_.end(); ++it) { |
+ for (SourceStateMap::iterator it = source_state_map_.begin(); |
+ it != source_state_map_.end(); ++it) { |
delete it->second; |
} |
- stream_parser_map_.clear(); |
+ source_state_map_.clear(); |
} |
void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { |
@@ -938,8 +1068,8 @@ bool ChunkDemuxer::CanEndOfStream_Locked() const { |
(!video_ || video_->CanEndOfStream()); |
} |
-void ChunkDemuxer::OnStreamParserInitDone(bool success, TimeDelta duration) { |
- DVLOG(1) << "OnStreamParserInitDone(" << success << ", " |
+void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { |
+ DVLOG(1) << "OnSourceInitDone(" << success << ", " |
<< duration.InSecondsF() << ")"; |
lock_.AssertAcquired(); |
DCHECK_EQ(state_, INITIALIZING); |
@@ -1036,9 +1166,6 @@ bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { |
return false; |
CHECK(IsValidId(source_id_audio_)); |
- AdjustBufferTimestamps( |
- buffers, source_info_map_[source_id_audio_].timestamp_offset); |
- |
if (!audio_->Append(buffers)) |
return false; |
@@ -1054,9 +1181,6 @@ bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { |
return false; |
CHECK(IsValidId(source_id_video_)); |
- AdjustBufferTimestamps( |
- buffers, source_info_map_[source_id_video_].timestamp_offset); |
- |
if (!video_->Append(buffers)) |
return false; |
@@ -1083,40 +1207,15 @@ void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, |
lock_.AssertAcquired(); |
CHECK(IsValidId(source_id)); |
- source_info_map_[source_id].can_update_offset = false; |
- base::TimeDelta start_timestamp = |
- timestamp + source_info_map_[source_id].timestamp_offset; |
- |
if (audio_ && source_id == source_id_audio_) |
- audio_->OnNewMediaSegment(start_timestamp); |
+ audio_->OnNewMediaSegment(timestamp); |
if (video_ && source_id == source_id_video_) |
- video_->OnNewMediaSegment(start_timestamp); |
-} |
- |
-void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) { |
- DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")"; |
- CHECK(IsValidId(source_id)); |
- source_info_map_[source_id].can_update_offset = true; |
-} |
- |
-void ChunkDemuxer::AdjustBufferTimestamps( |
- const StreamParser::BufferQueue& buffers, |
- base::TimeDelta timestamp_offset) { |
- if (timestamp_offset == base::TimeDelta()) |
- return; |
- |
- for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
- itr != buffers.end(); ++itr) { |
- (*itr)->SetDecodeTimestamp( |
- (*itr)->GetDecodeTimestamp() + timestamp_offset); |
- (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset); |
- } |
+ video_->OnNewMediaSegment(timestamp); |
} |
bool ChunkDemuxer::IsValidId(const std::string& source_id) const { |
lock_.AssertAcquired(); |
- return source_info_map_.count(source_id) > 0u && |
- stream_parser_map_.count(source_id) > 0u; |
+ return source_state_map_.count(source_id) > 0u; |
} |
void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) { |