Index: media/base/pipeline.cc |
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc |
index 9790c61cb5ca792c12d44a3f7b1b45392892565d..c171e405bf10d4e9c0cfaa246a59b6e2c5073ebf 100644 |
--- a/media/base/pipeline.cc |
+++ b/media/base/pipeline.cc |
@@ -21,6 +21,8 @@ |
#include "media/base/clock.h" |
#include "media/base/filter_collection.h" |
#include "media/base/media_log.h" |
+#include "media/base/text_decoder.h" |
+#include "media/base/text_renderer.h" |
#include "media/base/video_decoder.h" |
#include "media/base/video_decoder_config.h" |
#include "media/base/video_renderer.h" |
@@ -44,9 +46,11 @@ Pipeline::Pipeline(const scoped_refptr<base::MessageLoopProxy>& message_loop, |
status_(PIPELINE_OK), |
has_audio_(false), |
has_video_(false), |
+ has_text_(false), |
state_(kCreated), |
audio_ended_(false), |
video_ended_(false), |
+ text_ended_(false), |
audio_disabled_(false), |
demuxer_(NULL), |
creation_time_(default_tick_clock_.NowTicks()) { |
@@ -114,6 +118,11 @@ bool Pipeline::HasVideo() const { |
return has_video_; |
} |
+bool Pipeline::HasText() const { |
+ base::AutoLock auto_lock(lock_); |
+ return has_text_; |
+} |
+ |
float Pipeline::GetPlaybackRate() const { |
base::AutoLock auto_lock(lock_); |
return playback_rate_; |
@@ -232,6 +241,7 @@ const char* Pipeline::GetStateString(State state) { |
RETURN_STRING(kInitDemuxer); |
RETURN_STRING(kInitAudioRenderer); |
RETURN_STRING(kInitVideoRenderer); |
+ RETURN_STRING(kInitTextRenderer); |
RETURN_STRING(kInitPrerolling); |
RETURN_STRING(kSeeking); |
RETURN_STRING(kStarting); |
@@ -261,14 +271,23 @@ Pipeline::State Pipeline::GetNextState() const { |
return kInitAudioRenderer; |
if (demuxer_->GetStream(DemuxerStream::VIDEO)) |
return kInitVideoRenderer; |
+ if (demuxer_->GetStream(DemuxerStream::TEXT)) |
+ return kInitTextRenderer; |
return kInitPrerolling; |
case kInitAudioRenderer: |
if (demuxer_->GetStream(DemuxerStream::VIDEO)) |
return kInitVideoRenderer; |
+ if (demuxer_->GetStream(DemuxerStream::TEXT)) |
+ return kInitTextRenderer; |
return kInitPrerolling; |
case kInitVideoRenderer: |
+ if (demuxer_->GetStream(DemuxerStream::TEXT)) |
+ return kInitTextRenderer; |
+ return kInitPrerolling; |
+ |
+ case kInitTextRenderer: |
return kInitPrerolling; |
case kInitPrerolling: |
@@ -435,6 +454,9 @@ void Pipeline::StateTransitionTask(PipelineStatus status) { |
case kInitVideoRenderer: |
return InitializeVideoRenderer(done_cb); |
+ case kInitTextRenderer: |
+ return InitializeTextRenderer(done_cb); |
+ |
case kInitPrerolling: |
filter_collection_.reset(); |
{ |
@@ -449,6 +471,7 @@ void Pipeline::StateTransitionTask(PipelineStatus status) { |
// track. |
has_audio_ = audio_renderer_ != NULL && !audio_disabled_; |
has_video_ = video_renderer_ != NULL; |
+ has_text_ = text_renderer_ != NULL; |
} |
if (!audio_renderer_ && !video_renderer_) { |
done_cb.Run(PIPELINE_ERROR_COULD_NOT_RENDER); |
@@ -537,6 +560,10 @@ void Pipeline::DoSeek( |
bound_fns.Push(base::Bind( |
&VideoRenderer::Pause, base::Unretained(video_renderer_.get()))); |
} |
+ if (text_renderer_) { |
+ bound_fns.Push(base::Bind( |
+ &TextRenderer::Pause, base::Unretained(text_renderer_.get()))); |
+ } |
// Flush. |
if (audio_renderer_) { |
@@ -586,6 +613,11 @@ void Pipeline::DoPlay(const PipelineStatusCB& done_cb) { |
&VideoRenderer::Play, base::Unretained(video_renderer_.get()))); |
} |
+ if (text_renderer_) { |
+ bound_fns.Push(base::Bind( |
+ &TextRenderer::Play, base::Unretained(text_renderer_.get()))); |
+ } |
+ |
pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); |
} |
@@ -609,6 +641,11 @@ void Pipeline::DoStop(const PipelineStatusCB& done_cb) { |
&VideoRenderer::Stop, base::Unretained(video_renderer_.get()))); |
} |
+ if (text_renderer_) { |
+ bound_fns.Push(base::Bind( |
+ &TextRenderer::Stop, base::Unretained(text_renderer_.get()))); |
+ } |
+ |
pending_callbacks_ = SerialRunner::Run(bound_fns, done_cb); |
} |
@@ -625,6 +662,7 @@ void Pipeline::OnStopCompleted(PipelineStatus status) { |
filter_collection_.reset(); |
audio_renderer_.reset(); |
video_renderer_.reset(); |
+ text_renderer_.reset(); |
demuxer_ = NULL; |
// If we stop during initialization/seeking we want to run |seek_cb_| |
@@ -685,6 +723,13 @@ void Pipeline::OnVideoRendererEnded() { |
media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::VIDEO_ENDED)); |
} |
+void Pipeline::OnTextRendererEnded() { |
+ // Force post to process ended messages after current execution frame. |
+ message_loop_->PostTask(FROM_HERE, base::Bind( |
+ &Pipeline::DoTextRendererEnded, base::Unretained(this))); |
+ media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::TEXT_ENDED)); |
+} |
+ |
// Called from any thread. |
void Pipeline::OnUpdateStatistics(const PipelineStatistics& stats) { |
base::AutoLock auto_lock(lock_); |
@@ -802,6 +847,7 @@ void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
seek_cb_ = seek_cb; |
audio_ended_ = false; |
video_ended_ = false; |
+ text_ended_ = false; |
// Kick off seeking! |
{ |
@@ -845,6 +891,18 @@ void Pipeline::DoVideoRendererEnded() { |
RunEndedCallbackIfNeeded(); |
} |
+void Pipeline::DoTextRendererEnded() { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ |
+ if (state_ != kStarted) |
+ return; |
+ |
+ DCHECK(!text_ended_); |
+ text_ended_ = true; |
+ |
+ RunEndedCallbackIfNeeded(); |
+} |
+ |
void Pipeline::RunEndedCallbackIfNeeded() { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
@@ -854,6 +912,9 @@ void Pipeline::RunEndedCallbackIfNeeded() { |
if (video_renderer_ && !video_ended_) |
return; |
+ if (text_renderer_ && !text_ended_) |
+ return; |
+ |
{ |
base::AutoLock auto_lock(lock_); |
clock_->EndOfStream(); |
@@ -925,6 +986,16 @@ void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { |
base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); |
} |
+void Pipeline::InitializeTextRenderer(const PipelineStatusCB& done_cb) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ |
+ text_renderer_ = filter_collection_->GetTextRenderer(); |
+ text_renderer_->Initialize( |
+ demuxer_, |
+ done_cb, |
+ base::Bind(&Pipeline::OnTextRendererEnded, base::Unretained(this))); |
+} |
+ |
void Pipeline::OnAudioUnderflow() { |
if (!message_loop_->BelongsToCurrentThread()) { |
message_loop_->PostTask(FROM_HERE, base::Bind( |