Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(201)

Unified Diff: media/filters/chunk_demuxer.cc

Issue 23702007: Render inband text tracks in the media pipeline (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: incorporate aaron's comments (10/12) Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698