Index: media/filters/chunk_demuxer.cc |
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc |
index dbf1b031bec9d75e5d5cb2b82521d7c81b707366..0602cc52489e85416870d6419967788b79fe0f3c 100644 |
--- a/media/filters/chunk_demuxer.cc |
+++ b/media/filters/chunk_demuxer.cc |
@@ -17,7 +17,6 @@ |
#include "media/base/stream_parser_buffer.h" |
#include "media/base/video_decoder_config.h" |
#include "media/filters/stream_parser_factory.h" |
-#include "media/webm/webm_webvtt_parser.h" |
using base::TimeDelta; |
@@ -39,12 +38,18 @@ class SourceState { |
const CreateDemuxerStreamCB& create_demuxer_stream_cb, |
const IncreaseDurationCB& increase_duration_cb); |
+ // Called when a new text track has been parsed, so the demuxer can alert |
+ // the demuxer host. |
+ typedef base::Callback<void(ChunkDemuxerStream* stream, |
+ TextKind kind, |
+ const std::string& name, |
+ const std::string& language)> NewTextTrackCB; |
+ |
void 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 NewTextTrackCB& new_text_track_cb); |
// Appends new data to the StreamParser. |
// Returns true if the data was successfully appended. Returns false if an |
@@ -90,13 +95,18 @@ class SourceState { |
bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, |
const StreamParser::BufferQueue& video_buffers); |
+ void OnNewTextTrack(int text_track_num, |
+ TextKind kind, |
+ const std::string& name, |
+ const std::string& language); |
+ |
// Called by the |stream_parser_| when new text buffers have been parsed. It |
- // applies |timestamp_offset_| to all buffers in |buffers| and then calls |
- // |new_buffers_cb| with the modified buffers. |
+ // applies |timestamp_offset_| to all buffers in |buffers| and then appends |
+ // the (modified) buffers to the demuxer stream associated with |
+ // the track having |text_track_number|. |
// Returns true on a successful call. Returns false if an error occured while |
// processing the buffers. |
- bool OnTextBuffers(const StreamParser::NewTextBuffersCB& new_buffers_cb, |
- TextTrack* text_track, |
+ bool OnTextBuffers(int text_track_number, |
const StreamParser::BufferQueue& buffers); |
// Helper function that adds |timestamp_offset_| to each buffer in |buffers|. |
@@ -142,6 +152,11 @@ class SourceState { |
ChunkDemuxerStream* video_; |
bool video_needs_keyframe_; |
+ NewTextTrackCB new_text_track_cb_; |
+ |
+ typedef std::map<int, ChunkDemuxerStream*> TextStreamMap; |
+ TextStreamMap text_stream_map_; |
+ |
LogCB log_cb_; |
DISALLOW_COPY_AND_ASSIGN(SourceState); |
@@ -193,6 +208,7 @@ class ChunkDemuxerStream : public DemuxerStream { |
// Returns false if the new config should trigger an error. |
bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb); |
bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb); |
+ void UpdateTextConfig(const LogCB& log_cb); |
void MarkEndOfStream(); |
void UnmarkEndOfStream(); |
@@ -261,10 +277,10 @@ SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, |
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 NewTextTrackCB& new_text_track_cb) { |
StreamParser::NewBuffersCB audio_cb; |
+ new_text_track_cb_ = new_text_track_cb; |
stream_parser_->Init(init_cb, |
base::Bind(&SourceState::OnNewConfigs, |
@@ -274,9 +290,10 @@ void SourceState::Init(const StreamParser::InitCB& init_cb, |
base::Bind(&SourceState::OnNewBuffers, |
base::Unretained(this)), |
base::Bind(&SourceState::OnTextBuffers, |
- base::Unretained(this), text_cb), |
+ base::Unretained(this)), |
need_key_cb, |
- add_text_track_cb, |
+ base::Bind(&SourceState::OnNewTextTrack, |
+ base::Unretained(this)), |
base::Bind(&SourceState::OnNewMediaSegment, |
base::Unretained(this)), |
base::Bind(&SourceState::OnEndOfMediaSegment, |
@@ -432,6 +449,11 @@ bool SourceState::OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, |
if (video_) |
video_->OnNewMediaSegment(segment_timestamp); |
+ |
+ for (TextStreamMap::iterator itr = text_stream_map_.begin(); |
+ itr != text_stream_map_.end(); ++itr) { |
+ itr->second->OnNewMediaSegment(segment_timestamp); |
+ } |
} |
if (!filtered_audio.empty()) { |
@@ -450,15 +472,33 @@ bool SourceState::OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, |
} |
bool SourceState::OnTextBuffers( |
- const StreamParser::NewTextBuffersCB& new_buffers_cb, |
- TextTrack* text_track, |
+ int text_track_number, |
const StreamParser::BufferQueue& buffers) { |
- if (new_buffers_cb.is_null()) |
- return false; |
+ if (buffers.empty()) |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
nit: DCHECK(!buffers.empty()) instead.
Matthew Heaney (Chromium)
2013/10/17 05:46:44
Done.
Matthew Heaney (Chromium)
2013/10/17 05:46:44
Done.
|
+ return true; |
+ |
+ TextStreamMap::iterator itr = text_stream_map_.find(text_track_number); |
+ if (itr == text_stream_map_.end()) |
+ return true; |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
nit: I think this should return false. Doesn't thi
Matthew Heaney (Chromium)
2013/10/17 05:46:44
Done.
|
AdjustBufferTimestamps(buffers); |
- return new_buffers_cb.Run(text_track, buffers); |
+ return itr->second->Append(buffers); |
+} |
+ |
+void SourceState::OnNewTextTrack(int text_track_number, |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
I think this may need to be folded into OnNewConfi
Matthew Heaney (Chromium)
2013/10/17 05:46:44
I did an incomplete implementation. You can check
|
+ TextKind kind, |
+ const std::string& name, |
+ const std::string& language) { |
+ ChunkDemuxerStream* const text_stream = |
+ create_demuxer_stream_cb_.Run(DemuxerStream::TEXT); |
+ |
+ // Interpret NULL as meaning that inband text tracks are disabled. |
+ if (text_stream) { |
+ text_stream->UpdateTextConfig(log_cb_); |
+ text_stream_map_[text_track_number] = text_stream; |
+ new_text_track_cb_.Run(text_stream, kind, name, language); |
+ } |
} |
void SourceState::FilterWithAppendWindow( |
@@ -649,6 +689,16 @@ bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config, |
return stream_->UpdateVideoConfig(config); |
} |
+void ChunkDemuxerStream::UpdateTextConfig(const LogCB& log_cb) { |
+ DCHECK_EQ(type_, TEXT); |
+ base::AutoLock auto_lock(lock_); |
+ |
+ if (!stream_) { |
+ DCHECK_EQ(state_, UNINITIALIZED); |
+ stream_.reset(new SourceBufferStream(log_cb)); |
+ } |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
This needs to verify that kind and language haven'
Matthew Heaney (Chromium)
2013/10/17 05:46:44
See if I got OnNewConfigs right, then I can adjust
|
+} |
+ |
void ChunkDemuxerStream::MarkEndOfStream() { |
base::AutoLock auto_lock(lock_); |
stream_->MarkEndOfStream(); |
@@ -744,14 +794,14 @@ void ChunkDemuxerStream::CompletePendingReadIfPossible_Locked() { |
ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, |
const NeedKeyCB& need_key_cb, |
- const AddTextTrackCB& add_text_track_cb, |
+ bool enable_text, |
const LogCB& log_cb) |
: state_(WAITING_FOR_INIT), |
cancel_next_seek_(false), |
host_(NULL), |
open_cb_(open_cb), |
need_key_cb_(need_key_cb), |
- add_text_track_cb_(add_text_track_cb), |
+ enable_text_(enable_text), |
log_cb_(log_cb), |
duration_(kNoTimestamp()), |
user_specified_duration_(-1) { |
@@ -828,7 +878,11 @@ DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { |
if (type == DemuxerStream::AUDIO) |
return audio_.get(); |
- return NULL; |
+ if (!enable_text_ || text_stream_set_.empty()) |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
nit: I'd prefer to not return text tracks through
Matthew Heaney (Chromium)
2013/10/17 05:46:44
Done.
|
+ return NULL; |
+ |
+ TextStreamSet::iterator itr = text_stream_set_.begin(); |
+ return *itr; |
} |
TimeDelta ChunkDemuxer::GetStartTime() const { |
@@ -910,9 +964,8 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), |
has_audio, |
has_video, |
- base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), |
need_key_cb_, |
- add_text_track_cb_); |
+ base::Bind(&ChunkDemuxer::OnNewTextTrack, base::Unretained(this))); |
source_state_map_[id] = source_state.release(); |
return kOk; |
@@ -936,6 +989,8 @@ void ChunkDemuxer::RemoveId(const std::string& id) { |
video_->Shutdown(); |
source_id_video_.clear(); |
} |
+ |
+ // TODO(matthewjheaney): delete the text streams associated with this id |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
This needs to be addressed in this CL. If you let
Matthew Heaney (Chromium)
2013/10/17 05:46:44
I did a partial implementation. You can see if I'
|
} |
Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
@@ -1252,6 +1307,13 @@ ChunkDemuxer::~ChunkDemuxer() { |
delete it->second; |
} |
source_state_map_.clear(); |
+ |
+ TextStreamSet::iterator it = text_stream_set_.begin(); |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
This would go away if you let SourceState own the
Matthew Heaney (Chromium)
2013/10/17 05:46:44
Done.
|
+ while (it != text_stream_set_.end()) { |
+ ChunkDemuxerStream* text_stream = *it; |
+ text_stream_set_.erase(it++); |
+ delete text_stream; |
+ } |
} |
void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { |
@@ -1342,6 +1404,14 @@ ChunkDemuxer::CreateDemuxerStream(DemuxerStream::Type type) { |
video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO)); |
return video_.get(); |
break; |
+ case DemuxerStream::TEXT: { |
+ // TODO(matthewjheaney): we need to destroy this text stream |
+ ChunkDemuxerStream* text_stream = |
+ new ChunkDemuxerStream(DemuxerStream::TEXT); |
+ text_stream_set_.insert(text_stream); |
+ return text_stream; |
+ break; |
+ } |
case DemuxerStream::UNKNOWN: |
case DemuxerStream::NUM_TYPES: |
NOTREACHED(); |
@@ -1351,30 +1421,14 @@ ChunkDemuxer::CreateDemuxerStream(DemuxerStream::Type type) { |
return NULL; |
} |
-bool ChunkDemuxer::OnTextBuffers( |
- TextTrack* text_track, |
- const StreamParser::BufferQueue& buffers) { |
+void ChunkDemuxer::OnNewTextTrack(ChunkDemuxerStream* text_stream, |
+ TextKind kind, |
+ const std::string& name, |
+ const std::string& language) { |
lock_.AssertAcquired(); |
DCHECK_NE(state_, SHUTDOWN); |
- |
- // TODO(matthewjheaney): IncreaseDurationIfNecessary |
- |
- for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
- itr != buffers.end(); ++itr) { |
- const StreamParserBuffer* const buffer = itr->get(); |
- const TimeDelta start = buffer->timestamp(); |
- const TimeDelta end = start + buffer->duration(); |
- |
- std::string id, settings, content; |
- |
- WebMWebVTTParser::Parse(buffer->data(), |
- buffer->data_size(), |
- &id, &settings, &content); |
- |
- text_track->addWebVTTCue(start, end, id, content, settings); |
- } |
- |
- return true; |
+ DCHECK(text_stream_set_.find(text_stream) != text_stream_set_.end()); |
+ host_->AddTextStream(text_stream, kind, name, language); |
} |
bool ChunkDemuxer::IsValidId(const std::string& source_id) const { |
@@ -1428,6 +1482,11 @@ void ChunkDemuxer::StartReturningData() { |
if (video_) |
video_->StartReturningData(); |
+ |
+ for (TextStreamSet::iterator itr = text_stream_set_.begin(); |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
nit: Consider iterating over the SourceState objec
Matthew Heaney (Chromium)
2013/10/17 05:46:44
Done.
|
+ itr != text_stream_set_.end(); ++itr) { |
+ (*itr)->StartReturningData(); |
+ } |
} |
void ChunkDemuxer::AbortPendingReads() { |
@@ -1436,6 +1495,11 @@ void ChunkDemuxer::AbortPendingReads() { |
if (video_) |
video_->AbortReads(); |
+ |
+ for (TextStreamSet::iterator itr = text_stream_set_.begin(); |
acolwell GONE FROM CHROMIUM
2013/10/14 20:42:24
ditto for this & the other 2 methods below.
Matthew Heaney (Chromium)
2013/10/17 05:46:44
Done.
|
+ itr != text_stream_set_.end(); ++itr) { |
+ (*itr)->AbortReads(); |
+ } |
} |
void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) { |
@@ -1444,6 +1508,11 @@ void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) { |
if (video_) |
video_->Seek(seek_time); |
+ |
+ for (TextStreamSet::iterator itr = text_stream_set_.begin(); |
+ itr != text_stream_set_.end(); ++itr) { |
+ (*itr)->Seek(seek_time); |
+ } |
} |
void ChunkDemuxer::CompletePendingReadsIfPossible() { |
@@ -1452,6 +1521,11 @@ void ChunkDemuxer::CompletePendingReadsIfPossible() { |
if (video_) |
video_->CompletePendingReadIfPossible(); |
+ |
+ for (TextStreamSet::iterator itr = text_stream_set_.begin(); |
+ itr != text_stream_set_.end(); ++itr) { |
+ (*itr)->CompletePendingReadIfPossible(); |
+ } |
} |
} // namespace media |