diff options
author | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-04 06:15:41 +0000 |
---|---|---|
committer | acolwell@chromium.org <acolwell@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-04 06:15:41 +0000 |
commit | 14263fe6425f8078770836253747a0af5381cba0 (patch) | |
tree | 684341c42fbd103004def07f16f42f62bc87b7db /media | |
parent | b73f12c1a55cc2f8605b1db92108cfa7313c0185 (diff) | |
download | chromium_src-14263fe6425f8078770836253747a0af5381cba0.zip chromium_src-14263fe6425f8078770836253747a0af5381cba0.tar.gz chromium_src-14263fe6425f8078770836253747a0af5381cba0.tar.bz2 |
Refactor ChunkDemuxer initialization and buffer callbacks.
Simplifies SourceState initialization and removes code
that routes buffers through ChunkDemuxer on their way to
ChunkDemuxerStream. This is the first in a series of
changes to move the SourceBufferStreams from
ChunkDemuxerStream to SourceState.
BUG=239506
TESTS=All existing unittests and LayoutTests still pass.
Review URL: https://chromiumcodereview.appspot.com/18501010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@210137 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/filters/chunk_demuxer.cc | 517 | ||||
-rw-r--r-- | media/filters/chunk_demuxer.h | 19 |
2 files changed, 299 insertions, 237 deletions
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 7a9ed57..be5d45c 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -26,17 +26,26 @@ namespace media { // Contains state belonging to a source id. class SourceState { public: - explicit SourceState(scoped_ptr<StreamParser> stream_parser); + // Callback signature used to create ChunkDemuxerStreams. + typedef base::Callback<ChunkDemuxerStream*( + DemuxerStream::Type)> CreateDemuxerStreamCB; + + // Callback signature used to notify ChunkDemuxer of timestamps + // that may cause the duration to be updated. + typedef base::Callback<void( + TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB; + + SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb, + const CreateDemuxerStreamCB& create_demuxer_stream_cb, + const IncreaseDurationCB& increase_duration_cb); void Init(const StreamParser::InitCB& init_cb, - const StreamParser::NewConfigCB& config_cb, - const StreamParser::NewBuffersCB& audio_cb, - const StreamParser::NewBuffersCB& video_cb, + bool allow_audio, + bool allow_video, const StreamParser::NewTextBuffersCB& text_cb, const StreamParser::NeedKeyCB& need_key_cb, const AddTextTrackCB& add_text_track_cb, - const StreamParser::NewMediaSegmentCB& new_segment_cb, - const LogCB& log_cb); + const StreamParser::NewMediaSegmentCB& new_segment_cb); // Appends new data to the StreamParser. // Returns true if the data was successfully appended. Returns false if an @@ -54,6 +63,14 @@ class SourceState { TimeDelta timestamp_offset() const { return timestamp_offset_; } private: + // Called by the |stream_parser_| when a new initialization segment is + // encountered. + // Returns true on a successful call. Returns false if an error occured while + // processing decoder configurations. + bool OnNewConfigs(bool allow_audio, bool allow_video, + const AudioDecoderConfig& audio_config, + const VideoDecoderConfig& video_config); + // 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 @@ -66,10 +83,11 @@ class SourceState { // 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. + // Append() on either |audio_| or |video_| with the modified buffers based on + // the value of |type|. // Returns true on a successful call. Returns false if an error occured while // processing the buffers. - bool OnBuffers(const StreamParser::NewBuffersCB& new_buffers_cb, + bool OnBuffers(DemuxerStream::Type type, const StreamParser::BufferQueue& buffers); // Called by the |stream_parser_| when new text buffers have been parsed. It @@ -84,6 +102,9 @@ class SourceState { // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); + CreateDemuxerStreamCB create_demuxer_stream_cb_; + IncreaseDurationCB increase_duration_cb_; + // The offset to apply to media segment timestamps. TimeDelta timestamp_offset_; @@ -93,114 +114,19 @@ class SourceState { // 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::NewTextBuffersCB& text_cb, - const StreamParser::NeedKeyCB& need_key_cb, - const AddTextTrackCB& add_text_track_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), - base::Bind(&SourceState::OnTextBuffers, - base::Unretained(this), text_cb), - need_key_cb, - add_text_track_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); -} - -bool SourceState::OnTextBuffers( - const StreamParser::NewTextBuffersCB& new_buffers_cb, - TextTrack* text_track, - const StreamParser::BufferQueue& buffers) { - if (new_buffers_cb.is_null()) - return false; + ChunkDemuxerStream* audio_; + ChunkDemuxerStream* video_; - AdjustBufferTimestamps(buffers); + LogCB log_cb_; - return new_buffers_cb.Run(text_track, buffers); -} + DISALLOW_COPY_AND_ASSIGN(SourceState); +}; class ChunkDemuxerStream : public DemuxerStream { public: typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; - ChunkDemuxerStream(const AudioDecoderConfig& audio_config, - const LogCB& log_cb); - ChunkDemuxerStream(const VideoDecoderConfig& video_config, - const LogCB& log_cb); + explicit ChunkDemuxerStream(Type type); virtual ~ChunkDemuxerStream(); void AbortReadsAndSeekStream(TimeDelta seek_time); @@ -225,8 +151,8 @@ class ChunkDemuxerStream : public DemuxerStream { // Called when midstream config updates occur. // Returns true if the new config is accepted. // Returns false if the new config should trigger an error. - bool UpdateAudioConfig(const AudioDecoderConfig& config); - bool UpdateVideoConfig(const VideoDecoderConfig& config); + bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb); + bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb); void EndOfStream(); void CancelEndOfStream(); @@ -275,18 +201,209 @@ class ChunkDemuxerStream : public DemuxerStream { DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); }; -ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, - const LogCB& log_cb) - : type_(AUDIO), - state_(UNINITIALIZED) { - stream_.reset(new SourceBufferStream(audio_config, log_cb)); +SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, + const LogCB& log_cb, + const CreateDemuxerStreamCB& create_demuxer_stream_cb, + const IncreaseDurationCB& increase_duration_cb) + : create_demuxer_stream_cb_(create_demuxer_stream_cb), + increase_duration_cb_(increase_duration_cb), + can_update_offset_(true), + stream_parser_(stream_parser.release()), + audio_(NULL), + video_(NULL), + log_cb_(log_cb) { + DCHECK(!create_demuxer_stream_cb_.is_null()); + DCHECK(!increase_duration_cb_.is_null()); +} + +void SourceState::Init(const StreamParser::InitCB& init_cb, + bool allow_audio, + bool allow_video, + const StreamParser::NewTextBuffersCB& text_cb, + const StreamParser::NeedKeyCB& need_key_cb, + const AddTextTrackCB& add_text_track_cb, + const StreamParser::NewMediaSegmentCB& new_segment_cb) { + StreamParser::NewBuffersCB audio_cb; + StreamParser::NewBuffersCB video_cb; + + if (allow_audio) { + audio_cb = base::Bind(&SourceState::OnBuffers, + base::Unretained(this), DemuxerStream::AUDIO); + } + + if (allow_video) { + video_cb = base::Bind(&SourceState::OnBuffers, + base::Unretained(this), DemuxerStream::VIDEO); + } + + stream_parser_->Init(init_cb, + base::Bind(&SourceState::OnNewConfigs, + base::Unretained(this), + allow_audio, + allow_video), + audio_cb, + video_cb, + base::Bind(&SourceState::OnTextBuffers, + base::Unretained(this), text_cb), + need_key_cb, + add_text_track_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_); + } +} + +bool SourceState::OnNewConfigs(bool allow_audio, bool allow_video, + const AudioDecoderConfig& audio_config, + const VideoDecoderConfig& video_config) { + DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video + << ", " << audio_config.IsValidConfig() + << ", " << video_config.IsValidConfig() << ")"; + + if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { + DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; + return false; + } + + // Signal an error if we get configuration info for stream types that weren't + // specified in AddId() or more configs after a stream is initialized. + if (allow_audio != audio_config.IsValidConfig()) { + MEDIA_LOG(log_cb_) + << "Initialization segment" + << (audio_config.IsValidConfig() ? " has" : " does not have") + << " an audio track, but the mimetype" + << (allow_audio ? " specifies" : " does not specify") + << " an audio codec."; + return false; + } + + if (allow_video != video_config.IsValidConfig()) { + MEDIA_LOG(log_cb_) + << "Initialization segment" + << (video_config.IsValidConfig() ? " has" : " does not have") + << " a video track, but the mimetype" + << (allow_video ? " specifies" : " does not specify") + << " a video codec."; + return false; + } + + bool success = true; + if (audio_config.IsValidConfig()) { + if (!audio_) { + audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO); + + if (!audio_) { + DVLOG(1) << "Failed to create an audio stream."; + return false; + } + } + + success &= audio_->UpdateAudioConfig(audio_config, log_cb_); + } + + if (video_config.IsValidConfig()) { + if (!video_) { + video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO); + + if (!video_) { + DVLOG(1) << "Failed to create a video stream."; + return false; + } + } + + success &= video_->UpdateVideoConfig(video_config, log_cb_); + } + + DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); + return success; +} + +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(DemuxerStream::Type type, + const StreamParser::BufferQueue& buffers) { + DCHECK(!buffers.empty()); + AdjustBufferTimestamps(buffers); + + ChunkDemuxerStream* stream = NULL; + switch (type) { + case DemuxerStream::AUDIO: + stream = audio_; + break; + case DemuxerStream::VIDEO: + stream = video_; + break; + case DemuxerStream::UNKNOWN: + case DemuxerStream::NUM_TYPES: + NOTREACHED(); + return false; + } + + if (!stream->Append(buffers)) + return false; + increase_duration_cb_.Run(buffers.back()->GetTimestamp(), stream); + return true; +} + +bool SourceState::OnTextBuffers( + const StreamParser::NewTextBuffersCB& new_buffers_cb, + TextTrack* text_track, + const StreamParser::BufferQueue& buffers) { + if (new_buffers_cb.is_null()) + return false; + + AdjustBufferTimestamps(buffers); + + return new_buffers_cb.Run(text_track, buffers); } -ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, - const LogCB& log_cb) - : type_(VIDEO), +ChunkDemuxerStream::ChunkDemuxerStream(Type type) + : type_(type), state_(UNINITIALIZED) { - stream_.reset(new SourceBufferStream(video_config, log_cb)); } void ChunkDemuxerStream::AbortReadsAndSeekStream(TimeDelta seek_time) { @@ -356,17 +473,32 @@ Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges( return range.IntersectionWith(valid_time_range); } -bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { +bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config, + const LogCB& log_cb) { DCHECK(config.IsValidConfig()); DCHECK_EQ(type_, AUDIO); base::AutoLock auto_lock(lock_); + if (!stream_) { + DCHECK_EQ(state_, UNINITIALIZED); + stream_.reset(new SourceBufferStream(config, log_cb)); + return true; + } + return stream_->UpdateAudioConfig(config); } -bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config) { +bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config, + const LogCB& log_cb) { DCHECK(config.IsValidConfig()); DCHECK_EQ(type_, VIDEO); base::AutoLock auto_lock(lock_); + + if (!stream_) { + DCHECK_EQ(state_, UNINITIALIZED); + stream_.reset(new SourceBufferStream(config, log_cb)); + return true; + } + return stream_->UpdateVideoConfig(config); } @@ -637,33 +769,26 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, (has_video && !source_id_video_.empty())) return kReachedIdLimit; - StreamParser::NewBuffersCB audio_cb; - StreamParser::NewBuffersCB video_cb; - - if (has_audio) { + if (has_audio) source_id_audio_ = id; - audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers, - base::Unretained(this)); - } - if (has_video) { + if (has_video) source_id_video_ = id; - video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers, - base::Unretained(this)); - } - scoped_ptr<SourceState> source_state(new SourceState(stream_parser.Pass())); + scoped_ptr<SourceState> source_state( + new SourceState(stream_parser.Pass(), log_cb_, + base::Bind(&ChunkDemuxer::CreateDemuxerStream, + base::Unretained(this)), + base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, + base::Unretained(this)))); 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, + has_audio, + has_video, base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), need_key_cb_, add_text_track_cb_, - base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id), - log_cb_); + base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id)); source_state_map_[id] = source_state.release(); return kOk; @@ -1046,92 +1171,28 @@ void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); } -bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, - const AudioDecoderConfig& audio_config, - const VideoDecoderConfig& video_config) { - DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video - << ", " << audio_config.IsValidConfig() - << ", " << video_config.IsValidConfig() << ")"; - lock_.AssertAcquired(); - - if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { - DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; - return false; - } - - // Signal an error if we get configuration info for stream types that weren't - // specified in AddId() or more configs after a stream is initialized. - // Only allow a single audio config for now. - if (has_audio != audio_config.IsValidConfig()) { - MEDIA_LOG(log_cb_) - << "Initialization segment" - << (audio_config.IsValidConfig() ? " has" : " does not have") - << " an audio track, but the mimetype" - << (has_audio ? " specifies" : " does not specify") - << " an audio codec."; - return false; - } - - // Only allow a single video config for now. - if (has_video != video_config.IsValidConfig()) { - MEDIA_LOG(log_cb_) - << "Initialization segment" - << (video_config.IsValidConfig() ? " has" : " does not have") - << " a video track, but the mimetype" - << (has_video ? " specifies" : " does not specify") - << " a video codec."; - return false; - } - - bool success = true; - if (audio_config.IsValidConfig()) { - if (audio_) { - success &= audio_->UpdateAudioConfig(audio_config); - } else { - audio_.reset(new ChunkDemuxerStream(audio_config, log_cb_)); - } - } - - if (video_config.IsValidConfig()) { - if (video_) { - success &= video_->UpdateVideoConfig(video_config); - } else { - video_.reset(new ChunkDemuxerStream(video_config, log_cb_)); - } +ChunkDemuxerStream* +ChunkDemuxer::CreateDemuxerStream(DemuxerStream::Type type) { + switch (type) { + case DemuxerStream::AUDIO: + if (audio_) + return NULL; + audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO)); + return audio_.get(); + break; + case DemuxerStream::VIDEO: + if (video_) + return NULL; + video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO)); + return video_.get(); + break; + case DemuxerStream::UNKNOWN: + case DemuxerStream::NUM_TYPES: + NOTREACHED(); + return NULL; } - - DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); - return success; -} - -bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { - lock_.AssertAcquired(); - DCHECK_NE(state_, SHUTDOWN); - - if (!audio_) - return false; - - CHECK(IsValidId(source_id_audio_)); - if (!audio_->Append(buffers)) - return false; - - IncreaseDurationIfNecessary(buffers, audio_.get()); - return true; -} - -bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { - lock_.AssertAcquired(); - DCHECK_NE(state_, SHUTDOWN); - - if (!video_) - return false; - - CHECK(IsValidId(source_id_video_)); - if (!video_->Append(buffers)) - return false; - - IncreaseDurationIfNecessary(buffers, video_.get()); - return true; + NOTREACHED(); + return NULL; } bool ChunkDemuxer::OnTextBuffers( @@ -1187,10 +1248,10 @@ void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { } void ChunkDemuxer::IncreaseDurationIfNecessary( - const StreamParser::BufferQueue& buffers, + TimeDelta last_appended_buffer_timestamp, ChunkDemuxerStream* stream) { - DCHECK(!buffers.empty()); - if (buffers.back()->GetTimestamp() <= duration_) + DCHECK(last_appended_buffer_timestamp != kNoTimestamp()); + if (last_appended_buffer_timestamp <= duration_) return; Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration()); diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index 56f69c6..95f9298 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h @@ -155,11 +155,12 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { // SourceState callbacks. void OnSourceInitDone(bool success, base::TimeDelta duration); - bool OnNewConfigs(bool has_audio, bool has_video, - const AudioDecoderConfig& audio_config, - const VideoDecoderConfig& video_config); - bool OnAudioBuffers(const StreamParser::BufferQueue& buffers); - bool OnVideoBuffers(const StreamParser::BufferQueue& buffers); + + // Creates a DemuxerStream for the specified |type|. + // Returns a new ChunkDemuxerStream instance if a stream of this type + // has not been created before. Returns NULL otherwise. + ChunkDemuxerStream* CreateDemuxerStream(DemuxerStream::Type type); + bool OnTextBuffers(TextTrack* text_track, const StreamParser::BufferQueue& buffers); void OnNewMediaSegment(const std::string& source_id, @@ -176,11 +177,11 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { // Returns true if |source_id| is valid, false otherwise. bool IsValidId(const std::string& source_id) const; - // Increases |duration_| if the newly appended |buffers| exceed the current - // |duration_|. The |duration_| is set to the end buffered timestamp of - // |stream|. + // Increases |duration_| if |last_appended_buffer_timestamp| exceeds the + // current |duration_|. The |duration_| is set to the end buffered timestamp + // of |stream|. void IncreaseDurationIfNecessary( - const StreamParser::BufferQueue& buffers, + base::TimeDelta last_appended_buffer_timestamp, ChunkDemuxerStream* stream); // Decreases |duration_| if the buffered region is less than |duration_| when |